New upstream version 2.0.0~git20190204.1.2693389a+dfsg1
This commit is contained in:
parent
d8a8133ee5
commit
7084cb4b53
@ -1 +1 @@
|
||||
e21b72c95+debian
|
||||
2693389a+debian
|
||||
|
||||
@ -77,7 +77,7 @@ if ($ENV{BUILD_NUMBER})
|
||||
endif()
|
||||
set(WITH_LIBRARY_VERSIONING "ON")
|
||||
|
||||
set(RAW_VERSTION_STRING "2.0.0-rc4")
|
||||
set(RAW_VERSTION_STRING "2.0.0-dev5")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSTION_STRING)
|
||||
elseif(USE_VERSION_FROM_GIT_TAG)
|
||||
@ -482,7 +482,7 @@ if(WIN32)
|
||||
add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS)
|
||||
|
||||
set(CMAKE_USE_RELATIVE_PATH ON)
|
||||
if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*" OR ${CMAKE_GENERATOR} MATCHES "Ninja*")
|
||||
if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*" OR ${CMAKE_GENERATOR} MATCHES "Ninja*" OR ${CMAKE_GENERATOR} MATCHES "Unix Makefiles")
|
||||
set(CMAKE_PDB_BINARY_DIR ${CMAKE_BINARY_DIR})
|
||||
elseif (${CMAKE_GENERATOR} MATCHES "Visual Studio*")
|
||||
set(CMAKE_PDB_BINARY_DIR "${CMAKE_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}")
|
||||
@ -490,12 +490,6 @@ if(WIN32)
|
||||
message(FATAL_ERROR "Unknown generator ${CMAKE_GENERATOR}")
|
||||
endif()
|
||||
|
||||
# Set product and vendor for dll and exe version information.
|
||||
set(RC_VERSION_VENDOR ${VENDOR})
|
||||
set(RC_VERSION_PRODUCT ${PRODUCT})
|
||||
set(RC_VERSION_PATCH ${BUILD_NUMBER})
|
||||
set(RC_VERSION_DESCRIPTION ${GIT_REVISION})
|
||||
|
||||
string(TIMESTAMP RC_VERSION_YEAR "%Y")
|
||||
|
||||
if(NOT DEFINED CMAKE_WINDOWS_VERSION)
|
||||
@ -512,6 +506,12 @@ if(WIN32)
|
||||
add_definitions(-DWINVER=0x0A00 -D_WIN32_WINNT=0x0A00)
|
||||
endif()
|
||||
|
||||
# Set product and vendor for dll and exe version information.
|
||||
set(RC_VERSION_VENDOR ${VENDOR})
|
||||
set(RC_VERSION_PRODUCT ${PRODUCT})
|
||||
set(RC_VERSION_PATCH ${BUILD_NUMBER})
|
||||
set(RC_VERSION_DESCRIPTION "${FREERDP_VERSION_FULL} ${GIT_REVISION} ${CMAKE_WINDOWS_VERSION} ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
|
||||
if (FREERDP_EXTERNAL_SSL_PATH)
|
||||
set(OPENSSL_ROOT_DIR ${FREERDP_EXTERNAL_SSL_PATH})
|
||||
endif()
|
||||
@ -682,10 +682,6 @@ set(X11_FEATURE_DESCRIPTION "X11 client and server")
|
||||
set(WAYLAND_FEATURE_PURPOSE "Wayland")
|
||||
set(WAYLAND_FEATURE_DESCRIPTION "Wayland client")
|
||||
|
||||
set(DIRECTFB_FEATURE_TYPE "OPTIONAL")
|
||||
set(DIRECTFB_FEATURE_PURPOSE "DirectFB")
|
||||
set(DIRECTFB_FEATURE_DESCRIPTION "DirectFB client")
|
||||
|
||||
set(ZLIB_FEATURE_TYPE "REQUIRED")
|
||||
set(ZLIB_FEATURE_PURPOSE "compression")
|
||||
set(ZLIB_FEATURE_DESCRIPTION "data compression")
|
||||
@ -782,7 +778,6 @@ if(WIN32)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||
set(ZLIB_FEATURE_TYPE "DISABLED")
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(OSS_FEATURE_TYPE "DISABLED")
|
||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
@ -796,7 +791,6 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||
set(VAAPI_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
|
||||
@ -833,7 +827,6 @@ endif(UNIX AND NOT ANDROID)
|
||||
if(ANDROID)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(OSS_FEATURE_TYPE "DISABLED")
|
||||
set(ALSA_FEATURE_TYPE "DISABLED")
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
@ -848,10 +841,6 @@ endif()
|
||||
|
||||
find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION})
|
||||
find_feature(Wayland ${WAYLAND_FEATURE_TYPE} ${WAYLAND_FEATURE_PURPOSE} ${WAYLAND_FEATURE_DESCRIPTION})
|
||||
find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION})
|
||||
if (${WITH_DIRECTFB})
|
||||
message(WARNING "DIRECTFB is orphaned and not maintained see docs/README.directfb for details")
|
||||
endif()
|
||||
|
||||
find_feature(ZLIB ${ZLIB_FEATURE_TYPE} ${ZLIB_FEATURE_PURPOSE} ${ZLIB_FEATURE_DESCRIPTION})
|
||||
find_feature(OpenSSL ${OPENSSL_FEATURE_TYPE} ${OPENSSL_FEATURE_PURPOSE} ${OPENSSL_FEATURE_DESCRIPTION})
|
||||
@ -881,6 +870,10 @@ find_feature(soxr ${SOXR_FEATURE_TYPE} ${SOXR_FEATURE_PURPOSE} ${SOXR_FEATURE_DE
|
||||
|
||||
find_feature(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION})
|
||||
|
||||
if (WITH_OPENH264 AND NOT WITH_OPENH264_LOADING)
|
||||
set(WITH_OPENH264_LOADING OFF)
|
||||
endif (WITH_OPENH264 AND NOT WITH_OPENH264_LOADING)
|
||||
|
||||
if ((WITH_FFMPEG OR WITH_DSP_FFMPEG) AND NOT FFMPEG_FOUND)
|
||||
message(FATAL_ERROR "FFMPEG support requested but not detected")
|
||||
endif()
|
||||
@ -945,6 +938,7 @@ endif()
|
||||
if(OPENSSL_FOUND)
|
||||
add_definitions("-DWITH_OPENSSL")
|
||||
message(STATUS "Using OpenSSL Version: ${OPENSSL_VERSION}")
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
if(MBEDTLS_FOUND)
|
||||
@ -1062,7 +1056,7 @@ add_subdirectory(include)
|
||||
add_subdirectory(libfreerdp)
|
||||
|
||||
if (IOS)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.0")
|
||||
if (IOS_PLATFORM MATCHES "SIMULATOR")
|
||||
set(CMAKE_OSX_SYSROOT "iphonesimulator")
|
||||
else()
|
||||
|
||||
@ -93,11 +93,6 @@ static UINT audin_opensles_free(IAudinDevice* device)
|
||||
|
||||
WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device);
|
||||
|
||||
/* The function may have been called out of order,
|
||||
* ignore duplicate requests. */
|
||||
if (!opensles)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
free(opensles->device_name);
|
||||
free(opensles);
|
||||
return CHANNEL_RC_OK;
|
||||
@ -154,11 +149,6 @@ static UINT audin_opensles_set_format(IAudinDevice* device,
|
||||
(void*) device, (void*) format, FramesPerPacket);
|
||||
assert(format);
|
||||
|
||||
/* The function may have been called out of order, ignore
|
||||
* requests before the device is available. */
|
||||
if (!opensles)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
opensles->format = *format;
|
||||
|
||||
switch (format->wFormatTag)
|
||||
|
||||
@ -279,7 +279,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
|
||||
|
||||
err_out:
|
||||
|
||||
if (error && oss->rdpcontext)
|
||||
if (error && oss && oss->rdpcontext)
|
||||
setChannelError(oss->rdpcontext, error,
|
||||
"audin_oss_thread_func reported an error");
|
||||
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <MMSystem.h>
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/cmdline.h>
|
||||
|
||||
@ -216,7 +216,7 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s,
|
||||
UINT16 length, UINT16 flags)
|
||||
UINT32 length, UINT16 flags)
|
||||
{
|
||||
UINT16 index;
|
||||
UINT16 lengthCapability;
|
||||
@ -257,7 +257,6 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s,
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown cliprdr capability set: %"PRIu16"", capabilitySetType);
|
||||
return CHANNEL_RC_BAD_PROC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,7 +269,7 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s,
|
||||
UINT16 length, UINT16 flags)
|
||||
UINT32 length, UINT16 flags)
|
||||
{
|
||||
CLIPRDR_MONITOR_READY monitorReady;
|
||||
CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
|
||||
@ -587,10 +586,10 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s)
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_capabilities(CliprdrClientContext* context,
|
||||
CLIPRDR_CAPABILITIES* capabilities)
|
||||
const CLIPRDR_CAPABILITIES* capabilities)
|
||||
{
|
||||
wStream* s;
|
||||
CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet;
|
||||
const CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
|
||||
|
||||
@ -602,7 +601,7 @@ static UINT cliprdr_client_capabilities(CliprdrClientContext* context,
|
||||
|
||||
Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
|
||||
Stream_Write_UINT16(s, 0); /* pad1 */
|
||||
generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*)capabilities->capabilitySets;
|
||||
generalCapabilitySet = (const CLIPRDR_GENERAL_CAPABILITY_SET*)capabilities->capabilitySets;
|
||||
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */
|
||||
Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */
|
||||
Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */
|
||||
@ -617,7 +616,7 @@ static UINT cliprdr_client_capabilities(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_temp_directory(CliprdrClientContext* context,
|
||||
CLIPRDR_TEMP_DIRECTORY* tempDirectory)
|
||||
const CLIPRDR_TEMP_DIRECTORY* tempDirectory)
|
||||
{
|
||||
int length;
|
||||
wStream* s;
|
||||
@ -639,8 +638,8 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context,
|
||||
if (length > 520)
|
||||
length = 520;
|
||||
|
||||
Stream_Write(s, wszTempDir, length * 2);
|
||||
Stream_Zero(s, (520 - length) * 2);
|
||||
Stream_Write(s, wszTempDir, (size_t)length * 2);
|
||||
Stream_Zero(s, (520 - (size_t)length) * 2);
|
||||
free(wszTempDir);
|
||||
WLog_Print(cliprdr->log, WLOG_DEBUG, "TempDirectory: %s",
|
||||
tempDirectory->szTempDir);
|
||||
@ -653,15 +652,15 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_format_list(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_LIST* formatList)
|
||||
const CLIPRDR_FORMAT_LIST* formatList)
|
||||
{
|
||||
wStream* s;
|
||||
UINT32 index;
|
||||
int length = 0;
|
||||
UINT32 length = 0;
|
||||
int cchWideChar;
|
||||
LPWSTR lpWideCharStr;
|
||||
int formatNameSize;
|
||||
int formatNameLength;
|
||||
size_t formatNameSize;
|
||||
size_t formatNameLength;
|
||||
char* szFormatName;
|
||||
WCHAR* wszFormatName;
|
||||
BOOL asciiNames = FALSE;
|
||||
@ -703,8 +702,14 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context,
|
||||
wszFormatName = NULL;
|
||||
|
||||
if (szFormatName)
|
||||
formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName,
|
||||
0);
|
||||
{
|
||||
int rc = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0);
|
||||
|
||||
if (rc < 0)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
formatNameSize = (size_t)rc;
|
||||
}
|
||||
|
||||
if (formatNameSize > 15)
|
||||
formatNameSize = 15;
|
||||
@ -726,8 +731,14 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context,
|
||||
formatNameSize = 2;
|
||||
|
||||
if (format->formatName)
|
||||
formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL,
|
||||
0) * 2;
|
||||
{
|
||||
int rc = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0);
|
||||
|
||||
if (rc < 0)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
formatNameSize = (size_t)rc * 2;
|
||||
}
|
||||
|
||||
length += formatNameSize;
|
||||
}
|
||||
@ -771,14 +782,12 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_format_list_response(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
|
||||
const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
formatListResponse->msgType = CB_FORMAT_LIST_RESPONSE;
|
||||
formatListResponse->dataLen = 0;
|
||||
s = cliprdr_packet_new(formatListResponse->msgType,
|
||||
formatListResponse->msgFlags, formatListResponse->dataLen);
|
||||
s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE,
|
||||
formatListResponse->msgFlags, 0);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
@ -796,7 +805,7 @@ static UINT cliprdr_client_format_list_response(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context,
|
||||
CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
|
||||
const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
@ -821,7 +830,7 @@ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context,
|
||||
CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
|
||||
const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
@ -846,15 +855,12 @@ static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_format_data_request(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
|
||||
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
formatDataRequest->msgType = CB_FORMAT_DATA_REQUEST;
|
||||
formatDataRequest->msgFlags = 0;
|
||||
formatDataRequest->dataLen = 4;
|
||||
s = cliprdr_packet_new(formatDataRequest->msgType, formatDataRequest->msgFlags,
|
||||
formatDataRequest->dataLen);
|
||||
|
||||
s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
@ -873,12 +879,12 @@ static UINT cliprdr_client_format_data_request(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_format_data_response(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
|
||||
const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE;
|
||||
s = cliprdr_packet_new(formatDataResponse->msgType,
|
||||
|
||||
s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE,
|
||||
formatDataResponse->msgFlags, formatDataResponse->dataLen);
|
||||
|
||||
if (!s)
|
||||
@ -899,7 +905,7 @@ static UINT cliprdr_client_format_data_response(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context,
|
||||
CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
@ -933,7 +939,7 @@ static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context,
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
|
||||
const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
|
||||
{
|
||||
wStream* s;
|
||||
cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle;
|
||||
@ -989,7 +995,7 @@ static UINT cliprdr_virtual_channel_event_data_received(cliprdrPlugin* cliprdr,
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength))
|
||||
if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
|
||||
{
|
||||
Stream_Free(cliprdr->data_in, TRUE);
|
||||
cliprdr->data_in = NULL;
|
||||
@ -1100,6 +1106,17 @@ static DWORD WINAPI cliprdr_virtual_channel_client_thread(LPVOID arg)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void cliprdr_free_msg(void* obj)
|
||||
{
|
||||
wMessage* msg = (wMessage*)obj;
|
||||
|
||||
if (msg)
|
||||
{
|
||||
wStream* s = (wStream*)msg->wParam;
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -1109,6 +1126,7 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr,
|
||||
LPVOID pData, UINT32 dataLength)
|
||||
{
|
||||
UINT32 status;
|
||||
wObject obj = { 0 };
|
||||
status = cliprdr->channelEntryPoints.pVirtualChannelOpenEx(cliprdr->InitHandle,
|
||||
&cliprdr->OpenHandle, cliprdr->channelDef.name,
|
||||
cliprdr_virtual_channel_open_event_ex);
|
||||
@ -1120,7 +1138,8 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr,
|
||||
return status;
|
||||
}
|
||||
|
||||
cliprdr->queue = MessageQueue_New(NULL);
|
||||
obj.fnObjectFree = cliprdr_free_msg;
|
||||
cliprdr->queue = MessageQueue_New(&obj);
|
||||
|
||||
if (!cliprdr->queue)
|
||||
{
|
||||
|
||||
@ -1447,12 +1447,12 @@ static UINT drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc)
|
||||
{
|
||||
UINT status;
|
||||
|
||||
if (drdynvc->OpenHandle == 0)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
if (!drdynvc)
|
||||
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||
|
||||
if (drdynvc->OpenHandle == 0)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
if (!MessageQueue_PostQuit(drdynvc->queue, 0))
|
||||
{
|
||||
status = GetLastError();
|
||||
|
||||
@ -54,8 +54,7 @@
|
||||
static void drive_file_fix_path(WCHAR* path)
|
||||
{
|
||||
size_t i;
|
||||
size_t length;
|
||||
length = (int) _wcslen(path);
|
||||
size_t length = _wcslen(path);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
@ -80,10 +79,10 @@ static void drive_file_fix_path(WCHAR* path)
|
||||
}
|
||||
|
||||
static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path,
|
||||
UINT32 PathLength)
|
||||
size_t PathLength)
|
||||
{
|
||||
WCHAR* fullpath;
|
||||
UINT32 base_path_length;
|
||||
size_t base_path_length;
|
||||
|
||||
if (!base_path || !path)
|
||||
return NULL;
|
||||
@ -107,11 +106,10 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
|
||||
{
|
||||
WIN32_FIND_DATAW findFileData;
|
||||
BOOL ret = TRUE;
|
||||
INT len;
|
||||
HANDLE dir;
|
||||
WCHAR* fullpath;
|
||||
WCHAR* path_slash;
|
||||
UINT32 base_path_length;
|
||||
size_t base_path_length;
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
@ -140,7 +138,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path)
|
||||
|
||||
do
|
||||
{
|
||||
len = _wcslen(findFileData.cFileName);
|
||||
size_t len = _wcslen(findFileData.cFileName);
|
||||
|
||||
if ((len == 1 && findFileData.cFileName[0] == L'.') || (len == 2 &&
|
||||
findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.'))
|
||||
@ -335,7 +333,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat
|
||||
file->file_handle = INVALID_HANDLE_VALUE;
|
||||
file->find_handle = INVALID_HANDLE_VALUE;
|
||||
file->id = id;
|
||||
file->basepath = (WCHAR*) base_path;
|
||||
file->basepath = base_path;
|
||||
file->FileAttributes = FileAttributes;
|
||||
file->DesiredAccess = DesiredAccess;
|
||||
file->CreateDisposition = CreateDisposition;
|
||||
@ -397,7 +395,10 @@ BOOL drive_file_seek(DRIVE_FILE* file, UINT64 Offset)
|
||||
if (!file)
|
||||
return FALSE;
|
||||
|
||||
loffset.QuadPart = Offset;
|
||||
if (Offset > INT64_MAX)
|
||||
return FALSE;
|
||||
|
||||
loffset.QuadPart = (LONGLONG)Offset;
|
||||
return SetFilePointerEx(file->file_handle, loffset, NULL, FILE_BEGIN);
|
||||
}
|
||||
|
||||
@ -615,6 +616,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
liSize.QuadPart = size;
|
||||
|
||||
if (!SetFilePointerEx(file->file_handle, liSize, NULL, FILE_BEGIN))
|
||||
{
|
||||
WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError());
|
||||
@ -755,7 +758,10 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
|
||||
if (!Stream_EnsureRemainingCapacity(output, 4 + 64 + length))
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, 64 + length); /* Length */
|
||||
if (length > UINT32_MAX - 64)
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, (UINT32)(64 + length)); /* Length */
|
||||
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
|
||||
Stream_Write_UINT32(output, 0); /* FileIndex */
|
||||
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
|
||||
@ -771,7 +777,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
|
||||
Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
|
||||
Stream_Write_UINT32(output, length); /* FileNameLength */
|
||||
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
|
||||
Stream_Write(output, file->find_data.cFileName, length);
|
||||
break;
|
||||
|
||||
@ -781,23 +787,26 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
|
||||
if (!Stream_EnsureRemainingCapacity(output, 4 + 68 + length))
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, 68 + length); /* Length */
|
||||
if (length > UINT32_MAX - 68)
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, (UINT32)(68 + length)); /* Length */
|
||||
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
|
||||
Stream_Write_UINT32(output, 0); /* FileIndex */
|
||||
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwHighDateTime); /* CreationTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* ChangeTime */
|
||||
Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* ChangeTime */
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* EndOfFile */
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* EndOfFile */
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
|
||||
Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
|
||||
Stream_Write_UINT32(output, length); /* FileNameLength */
|
||||
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
|
||||
Stream_Write_UINT32(output, 0); /* EaSize */
|
||||
Stream_Write(output, file->find_data.cFileName, length);
|
||||
break;
|
||||
@ -808,7 +817,10 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
|
||||
if (!Stream_EnsureRemainingCapacity(output, 4 + 93 + length))
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, 93 + length); /* Length */
|
||||
if (length > UINT32_MAX - 93)
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, (UINT32)(93 + length)); /* Length */
|
||||
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
|
||||
Stream_Write_UINT32(output, 0); /* FileIndex */
|
||||
Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */
|
||||
@ -824,7 +836,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeLow); /* AllocationSize */
|
||||
Stream_Write_UINT32(output, file->find_data.nFileSizeHigh); /* AllocationSize */
|
||||
Stream_Write_UINT32(output, file->find_data.dwFileAttributes); /* FileAttributes */
|
||||
Stream_Write_UINT32(output, length); /* FileNameLength */
|
||||
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
|
||||
Stream_Write_UINT32(output, 0); /* EaSize */
|
||||
Stream_Write_UINT8(output, 0); /* ShortNameLength */
|
||||
/* Reserved(1), MUST NOT be added! */
|
||||
@ -838,14 +850,18 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT
|
||||
if (!Stream_EnsureRemainingCapacity(output, 4 + 12 + length))
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, 12 + length); /* Length */
|
||||
if (length > UINT32_MAX - 12)
|
||||
goto out_fail;
|
||||
|
||||
Stream_Write_UINT32(output, (UINT32)(12 + length)); /* Length */
|
||||
Stream_Write_UINT32(output, 0); /* NextEntryOffset */
|
||||
Stream_Write_UINT32(output, 0); /* FileIndex */
|
||||
Stream_Write_UINT32(output, length); /* FileNameLength */
|
||||
Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */
|
||||
Stream_Write(output, file->find_data.cFileName, length);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unhandled FsInformationClass %"PRIu32, FsInformationClass);
|
||||
/* Unhandled FsInformationClass */
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ struct _DRIVE_FILE
|
||||
HANDLE file_handle;
|
||||
HANDLE find_handle;
|
||||
WIN32_FIND_DATAW find_data;
|
||||
WCHAR* basepath;
|
||||
const WCHAR* basepath;
|
||||
WCHAR* fullpath;
|
||||
WCHAR* filename;
|
||||
BOOL delete_pending;
|
||||
|
||||
@ -84,7 +84,7 @@ static void printer_cups_get_printjob_name(char* buf, int size)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT printer_cups_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
|
||||
static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size)
|
||||
{
|
||||
rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*) printjob;
|
||||
|
||||
|
||||
@ -35,8 +35,10 @@
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/interlocked.h>
|
||||
#include <winpr/path.h>
|
||||
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
#include "../printer.h"
|
||||
|
||||
@ -71,6 +73,364 @@ struct _PRINTER_DEVICE
|
||||
char port[64];
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PRN_CONF_PORT = 0,
|
||||
PRN_CONF_PNP = 1,
|
||||
PRN_CONF_DRIVER = 2,
|
||||
PRN_CONF_DATA = 3
|
||||
}
|
||||
prn_conf_t;
|
||||
|
||||
static const char* filemap[] =
|
||||
{
|
||||
"PortDosName",
|
||||
"PnPName",
|
||||
"DriverName",
|
||||
"CachedPrinterConfigData"
|
||||
};
|
||||
|
||||
static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* name, size_t length)
|
||||
{
|
||||
char* dir = GetCombinedPath(settings->ConfigPath, "printers");
|
||||
char* bname = crypto_base64_encode((const BYTE*) name, (int)length);
|
||||
char* config = GetCombinedPath(dir, bname);
|
||||
|
||||
if (config && !PathFileExistsA(config))
|
||||
{
|
||||
if (!PathMakePathA(config, NULL))
|
||||
{
|
||||
free(config);
|
||||
config = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(bname);
|
||||
return config;
|
||||
}
|
||||
|
||||
static BOOL printer_write_setting(const char* path, prn_conf_t type, const void* data,
|
||||
size_t length)
|
||||
{
|
||||
DWORD written = 0;
|
||||
BOOL rc = FALSE;
|
||||
HANDLE file;
|
||||
size_t b64len;
|
||||
char* base64 = NULL;
|
||||
const char* name = filemap[type];
|
||||
char* abs = GetCombinedPath(path, name);
|
||||
|
||||
if (!abs)
|
||||
return FALSE;
|
||||
|
||||
file = CreateFileA(abs, GENERIC_WRITE, 0,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
free(abs);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
base64 = crypto_base64_encode(data, length);
|
||||
|
||||
if (!base64)
|
||||
goto fail;
|
||||
|
||||
b64len = strlen(base64);
|
||||
rc = WriteFile(file, base64, b64len, &written, NULL);
|
||||
|
||||
if (b64len != written)
|
||||
rc = FALSE;
|
||||
}
|
||||
else
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
CloseHandle(file);
|
||||
free(base64);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_config_valid(const char* path)
|
||||
{
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
if (!PathFileExistsA(path))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, size_t* length)
|
||||
{
|
||||
DWORD lowSize, highSize;
|
||||
DWORD read = 0;
|
||||
BOOL rc = FALSE;
|
||||
HANDLE file;
|
||||
BYTE* fdata = NULL;
|
||||
const char* name = filemap[type];
|
||||
char* abs = GetCombinedPath(path, name);
|
||||
|
||||
if (!abs)
|
||||
return FALSE;
|
||||
|
||||
file = CreateFileA(abs, GENERIC_READ, 0,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
free(abs);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
lowSize = GetFileSize(file, &highSize);
|
||||
|
||||
if ((lowSize == INVALID_FILE_SIZE) || (highSize != 0))
|
||||
goto fail;
|
||||
|
||||
if (lowSize != 0)
|
||||
{
|
||||
fdata = malloc(lowSize);
|
||||
|
||||
if (!fdata)
|
||||
goto fail;
|
||||
|
||||
rc = ReadFile(file, fdata, lowSize, &read, NULL);
|
||||
|
||||
if (lowSize != read)
|
||||
rc = FALSE;
|
||||
}
|
||||
|
||||
fail:
|
||||
CloseHandle(file);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
int blen = 0;
|
||||
crypto_base64_decode(fdata, lowSize, data, &blen);
|
||||
|
||||
if (*data)
|
||||
*length = blen;
|
||||
else
|
||||
{
|
||||
rc = FALSE;
|
||||
*length = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = 0;
|
||||
*data = NULL;
|
||||
}
|
||||
|
||||
free(fdata);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_save_to_config(const rdpSettings* settings,
|
||||
const char* PortDosName, size_t PortDosNameLen,
|
||||
const WCHAR* PnPName, size_t PnPNameLen,
|
||||
const WCHAR* DriverName, size_t DriverNameLen,
|
||||
const WCHAR* PrinterName, size_t PrintNameLen,
|
||||
const BYTE* CachedPrinterConfigData, size_t CacheFieldsLen)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = get_printer_config_path(settings, PrinterName, PrintNameLen);
|
||||
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_PORT, PortDosName, PortDosNameLen))
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_PNP, PnPName, PnPNameLen))
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_DRIVER, DriverName, DriverNameLen))
|
||||
goto fail;
|
||||
|
||||
if (!printer_write_setting(path, PRN_CONF_DATA, CachedPrinterConfigData, CacheFieldsLen))
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_update_to_config(const rdpSettings* settings, const WCHAR* name, size_t length,
|
||||
const BYTE* data, size_t datalen)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = get_printer_config_path(settings, name, length);
|
||||
rc = printer_write_setting(path, PRN_CONF_DATA, data, datalen);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name, size_t length)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = get_printer_config_path(settings, name, length);
|
||||
|
||||
if (!printer_config_valid(path))
|
||||
goto fail;
|
||||
|
||||
rc = RemoveDirectoryA(path);
|
||||
fail:
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldName, size_t oldLength,
|
||||
const WCHAR* newName, size_t newLength)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* oldPath = get_printer_config_path(settings, oldName, oldLength);
|
||||
char* newPath = get_printer_config_path(settings, newName, newLength);
|
||||
|
||||
if (printer_config_valid(oldPath))
|
||||
rc = MoveFileA(oldPath, newPath);
|
||||
|
||||
free(oldPath);
|
||||
free(newPath);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* printer,
|
||||
PRINTER_DEVICE* printer_dev)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
WCHAR* wname = NULL;
|
||||
size_t wlen;
|
||||
char* path = NULL;
|
||||
int rc;
|
||||
UINT32 flags = 0;
|
||||
WCHAR* DriverName = NULL;
|
||||
size_t DriverNameLen = 0;
|
||||
WCHAR* PnPName = NULL;
|
||||
size_t PnPNameLen = 0;
|
||||
BYTE* CachedPrinterConfigData = NULL;
|
||||
size_t CachedFieldsLen = 0;
|
||||
size_t PrinterNameLen = 0;
|
||||
|
||||
if (!settings || !printer)
|
||||
return FALSE;
|
||||
|
||||
rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);
|
||||
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
|
||||
wlen = _wcslen(wname) + 1;
|
||||
path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
|
||||
PrinterNameLen = (wlen + 1) * sizeof(WCHAR);
|
||||
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
if (printer->is_default)
|
||||
flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
|
||||
|
||||
if (!printer_read_setting(path, PRN_CONF_PNP, &PnPName, &PnPNameLen))
|
||||
{
|
||||
}
|
||||
|
||||
if (!printer_read_setting(path, PRN_CONF_DRIVER, &DriverName, &DriverNameLen))
|
||||
{
|
||||
DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName,
|
||||
0) * 2 + 1;
|
||||
}
|
||||
|
||||
if (!printer_read_setting(path, PRN_CONF_DATA, &CachedPrinterConfigData, &CachedFieldsLen))
|
||||
{
|
||||
}
|
||||
|
||||
Stream_SetPosition(printer_dev->device.data, 0);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, 24))
|
||||
goto fail;
|
||||
|
||||
Stream_Write_UINT32(printer_dev->device.data, flags);
|
||||
Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */
|
||||
Stream_Write_UINT32(printer_dev->device.data, PnPNameLen); /* PnPNameLen */
|
||||
Stream_Write_UINT32(printer_dev->device.data, DriverNameLen);
|
||||
Stream_Write_UINT32(printer_dev->device.data, PrinterNameLen);
|
||||
Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PnPNameLen))
|
||||
goto fail;
|
||||
|
||||
if (PnPNameLen > 0)
|
||||
Stream_Write(printer_dev->device.data, PnPName, PnPNameLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, DriverNameLen))
|
||||
goto fail;
|
||||
|
||||
Stream_Write(printer_dev->device.data, DriverName, DriverNameLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PrinterNameLen))
|
||||
goto fail;
|
||||
|
||||
Stream_Write(printer_dev->device.data, wname, PrinterNameLen);
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, CachedFieldsLen))
|
||||
goto fail;
|
||||
|
||||
Stream_Write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen);
|
||||
res = TRUE;
|
||||
fail:
|
||||
free(path);
|
||||
free(wname);
|
||||
free(PnPName);
|
||||
free(DriverName);
|
||||
free(CachedPrinterConfigData);
|
||||
return res;
|
||||
}
|
||||
|
||||
static BOOL printer_save_default_config(const rdpSettings* settings, rdpPrinter* printer)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
WCHAR* wname = NULL;
|
||||
WCHAR* driver = NULL;
|
||||
size_t wlen, dlen;
|
||||
char* path = NULL;
|
||||
int rc;
|
||||
|
||||
if (!settings || !printer)
|
||||
return FALSE;
|
||||
|
||||
rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);
|
||||
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
|
||||
rc = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &driver, 0);
|
||||
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
|
||||
wlen = _wcslen(wname) + 1;
|
||||
dlen = _wcslen(driver) + 1;
|
||||
path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
|
||||
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
if (dlen > 1)
|
||||
{
|
||||
if (!printer_write_setting(path, PRN_CONF_DRIVER, driver, dlen * sizeof(WCHAR)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = TRUE;
|
||||
fail:
|
||||
free(path);
|
||||
free(wname);
|
||||
free(driver);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -293,6 +653,182 @@ static UINT printer_irp_request(DEVICE* device, IRP* irp)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 packetId, wStream* s)
|
||||
{
|
||||
UINT32 eventID;
|
||||
PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device;
|
||||
const rdpSettings* settings = printer_dev->rdpcontext->settings;
|
||||
|
||||
if (component != RDPDR_CTYP_PRN)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, eventID);
|
||||
|
||||
switch (packetId)
|
||||
{
|
||||
case PAKID_PRN_CACHE_DATA:
|
||||
switch (eventID)
|
||||
{
|
||||
case RDPDR_ADD_PRINTER_EVENT:
|
||||
{
|
||||
char PortDosName[8];
|
||||
UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen;
|
||||
const WCHAR* PnPName, *DriverName, *PrinterName;
|
||||
const BYTE* CachedPrinterConfigData;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 24)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read(s, PortDosName, sizeof(PortDosName));
|
||||
Stream_Read_UINT32(s, PnPNameLen);
|
||||
Stream_Read_UINT32(s, DriverNameLen);
|
||||
Stream_Read_UINT32(s, PrintNameLen);
|
||||
Stream_Read_UINT32(s, CacheFieldsLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PnPNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PnPName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PnPNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < DriverNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
DriverName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, DriverNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PrintNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PrintNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < CacheFieldsLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
CachedPrinterConfigData = Stream_Pointer(s);
|
||||
Stream_Seek(s, CacheFieldsLen);
|
||||
|
||||
if (!printer_save_to_config(settings,
|
||||
PortDosName, sizeof(PortDosName),
|
||||
PnPName, PnPNameLen,
|
||||
DriverName, DriverNameLen,
|
||||
PrinterName, PrintNameLen,
|
||||
CachedPrinterConfigData, CacheFieldsLen))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPDR_UPDATE_PRINTER_EVENT:
|
||||
{
|
||||
UINT32 PrinterNameLen, ConfigDataLen;
|
||||
const WCHAR* PrinterName;
|
||||
const BYTE* ConfigData;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, PrinterNameLen);
|
||||
Stream_Read_UINT32(s, ConfigDataLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < ConfigDataLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
ConfigData = Stream_Pointer(s);
|
||||
Stream_Seek(s, ConfigDataLen);
|
||||
|
||||
if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData, ConfigDataLen))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPDR_DELETE_PRINTER_EVENT:
|
||||
{
|
||||
UINT32 PrinterNameLen;
|
||||
const WCHAR* PrinterName;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, PrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < PrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
PrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, PrinterNameLen);
|
||||
printer_remove_config(settings, PrinterName, PrinterNameLen);
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPDR_RENAME_PRINTER_EVENT:
|
||||
{
|
||||
UINT32 OldPrinterNameLen, NewPrinterNameLen;
|
||||
const WCHAR* OldPrinterName;
|
||||
const WCHAR* NewPrinterName;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, OldPrinterNameLen);
|
||||
Stream_Read_UINT32(s, NewPrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < OldPrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
OldPrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, OldPrinterNameLen);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < NewPrinterNameLen)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
NewPrinterName = (const WCHAR*)Stream_Pointer(s);
|
||||
Stream_Seek(s, NewPrinterNameLen);
|
||||
|
||||
if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen, NewPrinterName,
|
||||
NewPrinterNameLen))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown cache data eventID: 0x%08"PRIX32"", eventID);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PAKID_PRN_USING_XPS:
|
||||
{
|
||||
UINT32 flags;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, flags);
|
||||
WLog_ERR(TAG,
|
||||
"Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08"PRIx32", flags=%08"PRIx32"]",
|
||||
eventID, flags);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -309,7 +845,13 @@ static UINT printer_free(DEVICE* device)
|
||||
{
|
||||
error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error);
|
||||
|
||||
/* The analyzer is confused by this premature return value.
|
||||
* Since this case can not be handled gracefully silence the
|
||||
* analyzer here. */
|
||||
#ifndef __clang_analyzer__
|
||||
return error;
|
||||
#endif
|
||||
}
|
||||
|
||||
while ((irp = (IRP*) InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL)
|
||||
@ -336,15 +878,8 @@ static UINT printer_free(DEVICE* device)
|
||||
UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
rdpPrinter* printer)
|
||||
{
|
||||
UINT32 Flags;
|
||||
int DriverNameLen;
|
||||
WCHAR* DriverName = NULL;
|
||||
int PrintNameLen;
|
||||
WCHAR* PrintName = NULL;
|
||||
UINT32 CachedFieldsLen;
|
||||
BYTE* CachedPrinterConfigData;
|
||||
PRINTER_DEVICE* printer_dev;
|
||||
UINT error;
|
||||
UINT error = ERROR_INTERNAL_ERROR;
|
||||
printer_dev = (PRINTER_DEVICE*) calloc(1, sizeof(PRINTER_DEVICE));
|
||||
|
||||
if (!printer_dev)
|
||||
@ -353,55 +888,19 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
printer_dev->device.data = Stream_New(NULL, 1024);
|
||||
|
||||
if (!printer_dev->device.data)
|
||||
goto error_out;
|
||||
|
||||
sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%d", printer->id);
|
||||
printer_dev->device.type = RDPDR_DTYP_PRINT;
|
||||
printer_dev->device.name = printer_dev->port;
|
||||
printer_dev->device.IRPRequest = printer_irp_request;
|
||||
printer_dev->device.CustomComponentRequest = printer_custom_component;
|
||||
printer_dev->device.Free = printer_free;
|
||||
printer_dev->rdpcontext = pEntryPoints->rdpcontext;
|
||||
printer_dev->printer = printer;
|
||||
CachedFieldsLen = 0;
|
||||
CachedPrinterConfigData = NULL;
|
||||
Flags = 0;
|
||||
|
||||
if (printer->is_default)
|
||||
Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
|
||||
|
||||
DriverNameLen = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &DriverName,
|
||||
0) * 2;
|
||||
PrintNameLen = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &PrintName,
|
||||
0) * 2;
|
||||
printer_dev->device.data = Stream_New(NULL,
|
||||
28 + DriverNameLen + PrintNameLen + CachedFieldsLen);
|
||||
|
||||
if (!printer_dev->device.data)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
free(DriverName);
|
||||
free(PrintName);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(printer_dev->device.data, Flags);
|
||||
Stream_Write_UINT32(printer_dev->device.data, 0); /* CodePage, reserved */
|
||||
Stream_Write_UINT32(printer_dev->device.data, 0); /* PnPNameLen */
|
||||
Stream_Write_UINT32(printer_dev->device.data, DriverNameLen + 2);
|
||||
Stream_Write_UINT32(printer_dev->device.data, PrintNameLen + 2);
|
||||
Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen);
|
||||
Stream_Write(printer_dev->device.data, DriverName, DriverNameLen);
|
||||
Stream_Write_UINT16(printer_dev->device.data, 0);
|
||||
Stream_Write(printer_dev->device.data, PrintName, PrintNameLen);
|
||||
Stream_Write_UINT16(printer_dev->device.data, 0);
|
||||
|
||||
if (CachedFieldsLen > 0)
|
||||
{
|
||||
Stream_Write(printer_dev->device.data, CachedPrinterConfigData,
|
||||
CachedFieldsLen);
|
||||
}
|
||||
|
||||
free(DriverName);
|
||||
free(PrintName);
|
||||
printer_dev->pIrpList = (WINPR_PSLIST_HEADER) _aligned_malloc(sizeof(
|
||||
WINPR_SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
|
||||
|
||||
@ -412,6 +911,9 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints,
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!printer_load_from_config(pEntryPoints->rdpcontext->settings, printer, printer_dev))
|
||||
goto error_out;
|
||||
|
||||
InitializeSListHead(printer_dev->pIrpList);
|
||||
|
||||
if (!(printer_dev->event = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
@ -497,6 +999,9 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer))
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
|
||||
if ((error = printer_register(pEntryPoints, printer)))
|
||||
{
|
||||
WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error);
|
||||
|
||||
@ -54,7 +54,7 @@ struct rdp_printer
|
||||
pcFreePrinter Free;
|
||||
};
|
||||
|
||||
typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, BYTE* data, int size);
|
||||
typedef UINT (*pcWritePrintJob) (rdpPrintJob* printjob, const BYTE* data, size_t size);
|
||||
typedef void (*pcClosePrintJob) (rdpPrintJob* printjob);
|
||||
|
||||
struct rdp_print_job
|
||||
|
||||
@ -68,8 +68,8 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
|
||||
|
||||
devman->plugin = (void*) rdpdr;
|
||||
devman->id_sequence = 1;
|
||||
|
||||
devman->devices = ListDictionary_New(TRUE);
|
||||
|
||||
if (!devman->devices)
|
||||
{
|
||||
WLog_INFO(TAG, "ListDictionary_New failed!");
|
||||
@ -78,7 +78,6 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr)
|
||||
}
|
||||
|
||||
ListDictionary_ValueObject(devman->devices)->fnObjectFree = devman_device_free;
|
||||
|
||||
return devman;
|
||||
}
|
||||
|
||||
@ -114,26 +113,57 @@ static UINT devman_register_device(DEVMAN* devman, DEVICE* device)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
device->id = devman->id_sequence++;
|
||||
key = (void*) (size_t) device->id;
|
||||
key = (void*)(size_t) device->id;
|
||||
|
||||
if (!ListDictionary_Add(devman->devices, key, device))
|
||||
{
|
||||
WLog_INFO(TAG, "ListDictionary_Add failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id)
|
||||
{
|
||||
DEVICE* device = NULL;
|
||||
void* key = (void*) (size_t) id;
|
||||
void* key = (void*)(size_t) id;
|
||||
|
||||
if (!devman)
|
||||
return NULL;
|
||||
|
||||
device = (DEVICE*) ListDictionary_GetItemValue(devman->devices, key);
|
||||
return device;
|
||||
}
|
||||
|
||||
DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type)
|
||||
{
|
||||
DEVICE* device = NULL;
|
||||
ULONG_PTR* keys;
|
||||
int count, x;
|
||||
|
||||
if (!devman)
|
||||
return NULL;
|
||||
|
||||
ListDictionary_Lock(devman->devices);
|
||||
count = ListDictionary_GetKeys(devman->devices, &keys);
|
||||
|
||||
for (x = 0; x < count; x++)
|
||||
{
|
||||
DEVICE* cur = (DEVICE*) ListDictionary_GetItemValue(devman->devices, (void*)keys[x]);
|
||||
|
||||
if (!cur)
|
||||
continue;
|
||||
|
||||
if (cur->type != type)
|
||||
continue;
|
||||
|
||||
device = cur;
|
||||
break;
|
||||
}
|
||||
|
||||
free(keys);
|
||||
ListDictionary_Unlock(devman->devices);
|
||||
return device;
|
||||
}
|
||||
|
||||
@ -178,7 +208,9 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext
|
||||
WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name);
|
||||
else
|
||||
WLog_INFO(TAG, "Loading device service %s (static)", ServiceName);
|
||||
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0);
|
||||
|
||||
entry = (PDEVICE_SERVICE_ENTRY) freerdp_load_channel_addin_entry(ServiceName, NULL,
|
||||
"DeviceServiceEntry", 0);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
@ -190,6 +222,5 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext
|
||||
ep.RegisterDevice = devman_register_device;
|
||||
ep.device = device;
|
||||
ep.rdpcontext = rdpcontext;
|
||||
|
||||
return entry(&ep);
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
void devman_unregister_device(DEVMAN* devman, void* key);
|
||||
UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext);
|
||||
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id);
|
||||
DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type);
|
||||
|
||||
DEVMAN* devman_new(rdpdrPlugin* rdpdr);
|
||||
void devman_free(DEVMAN* devman);
|
||||
|
||||
@ -135,7 +135,8 @@ BOOL check_path(char* path)
|
||||
{
|
||||
UINT type = GetDriveTypeA(path);
|
||||
|
||||
if (!(type == DRIVE_FIXED ||type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE))
|
||||
if (!(type == DRIVE_FIXED || type == DRIVE_REMOVABLE || type == DRIVE_CDROM ||
|
||||
type == DRIVE_REMOTE))
|
||||
return FALSE;
|
||||
|
||||
return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
|
||||
@ -1324,6 +1325,31 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s)
|
||||
return error;
|
||||
}
|
||||
|
||||
static UINT rdpdr_process_component(rdpdrPlugin* rdpdr, UINT16 component, UINT16 packetId,
|
||||
wStream* s)
|
||||
{
|
||||
UINT32 type;
|
||||
DEVICE* device;
|
||||
|
||||
switch (component)
|
||||
{
|
||||
case RDPDR_CTYP_PRN:
|
||||
type = RDPDR_DTYP_PRINT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
device = devman_get_device_by_type(rdpdr->devman, type);
|
||||
|
||||
if (!device)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return IFCALLRESULT(ERROR_INVALID_PARAMETER, device->CustomComponentRequest, device, component,
|
||||
packetId, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -1368,141 +1394,114 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s)
|
||||
UINT16 packetId;
|
||||
UINT32 deviceId;
|
||||
UINT32 status;
|
||||
UINT error;
|
||||
UINT error = ERROR_INVALID_DATA;
|
||||
|
||||
if (!rdpdr || !s)
|
||||
return CHANNEL_RC_NULL_DATA;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT16(s, component); /* Component (2 bytes) */
|
||||
Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
|
||||
|
||||
if (component == RDPDR_CTYP_CORE)
|
||||
if (Stream_GetRemainingLength(s) >= 4)
|
||||
{
|
||||
switch (packetId)
|
||||
Stream_Read_UINT16(s, component); /* Component (2 bytes) */
|
||||
Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */
|
||||
|
||||
if (component == RDPDR_CTYP_CORE)
|
||||
{
|
||||
case PAKID_CORE_SERVER_ANNOUNCE:
|
||||
if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
|
||||
return error;
|
||||
switch (packetId)
|
||||
{
|
||||
case PAKID_CORE_SERVER_ANNOUNCE:
|
||||
if ((error = rdpdr_process_server_announce_request(rdpdr, s)))
|
||||
{
|
||||
}
|
||||
else if ((error = rdpdr_send_client_announce_reply(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error);
|
||||
}
|
||||
else if ((error = rdpdr_send_client_name_request(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error);
|
||||
}
|
||||
else if ((error = rdpdr_process_init(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error);
|
||||
}
|
||||
|
||||
if ((error = rdpdr_send_client_announce_reply(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
||||
if ((error = rdpdr_send_client_name_request(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
case PAKID_CORE_SERVER_CAPABILITY:
|
||||
if ((error = rdpdr_process_capability_request(rdpdr, s)))
|
||||
{
|
||||
}
|
||||
else if ((error = rdpdr_send_capability_response(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error);
|
||||
}
|
||||
|
||||
if ((error = rdpdr_process_init(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case PAKID_CORE_CLIENTID_CONFIRM:
|
||||
if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
|
||||
{
|
||||
}
|
||||
else if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
}
|
||||
|
||||
case PAKID_CORE_SERVER_CAPABILITY:
|
||||
if ((error = rdpdr_process_capability_request(rdpdr, s)))
|
||||
return error;
|
||||
break;
|
||||
|
||||
if ((error = rdpdr_send_capability_response(rdpdr)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
case PAKID_CORE_USER_LOGGEDON:
|
||||
if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAKID_CORE_CLIENTID_CONFIRM:
|
||||
if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s)))
|
||||
return error;
|
||||
case PAKID_CORE_DEVICE_REPLY:
|
||||
|
||||
if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
/* connect to a specific resource */
|
||||
if (Stream_GetRemainingLength(s) >= 8)
|
||||
{
|
||||
Stream_Read_UINT32(s, deviceId);
|
||||
Stream_Read_UINT32(s, status);
|
||||
error = CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAKID_CORE_USER_LOGGEDON:
|
||||
if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %"PRIu32"",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
case PAKID_CORE_DEVICE_IOREQUEST:
|
||||
if ((error = rdpdr_process_irp(rdpdr, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_irp failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
else
|
||||
s = NULL;
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_REPLY:
|
||||
|
||||
/* connect to a specific resource */
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, deviceId);
|
||||
Stream_Read_UINT32(s, status);
|
||||
break;
|
||||
|
||||
case PAKID_CORE_DEVICE_IOREQUEST:
|
||||
if ((error = rdpdr_process_irp(rdpdr, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpdr_process_irp failed with error %"PRIu32"", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
s = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04"PRIX16"", packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
break;
|
||||
default:
|
||||
WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04"PRIX16"", packetId);
|
||||
error = ERROR_INVALID_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (component == RDPDR_CTYP_PRN)
|
||||
{
|
||||
switch (packetId)
|
||||
else
|
||||
{
|
||||
case PAKID_PRN_CACHE_DATA:
|
||||
{
|
||||
UINT32 eventID;
|
||||
error = rdpdr_process_component(rdpdr, component, packetId, s);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, eventID);
|
||||
WLog_ERR(TAG,
|
||||
"Ignoring unhandled message PAKID_PRN_CACHE_DATA (EventID: 0x%08"PRIX32")", eventID);
|
||||
}
|
||||
break;
|
||||
|
||||
case PAKID_PRN_USING_XPS:
|
||||
WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_USING_XPS");
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown printing component packetID: 0x%04"PRIX16"", packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Unknown message: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", component,
|
||||
packetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Unknown message: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", component,
|
||||
packetId);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
return CHANNEL_RC_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -243,10 +243,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
|
||||
h264.bitstream[1].length = Stream_GetRemainingLength(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
h264.bitstream[0].length = Stream_GetRemainingLength(s);
|
||||
memset(&h264.bitstream[1], 0, sizeof(h264.bitstream[1]));
|
||||
}
|
||||
|
||||
cmd->extra = (void*) &h264;
|
||||
|
||||
|
||||
@ -29,8 +29,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <MMSystem.h>
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/cmdline.h>
|
||||
@ -102,14 +102,12 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO
|
||||
|
||||
case MM_WOM_CLOSE:
|
||||
WLog_DBG(TAG, "MM_WOM_CLOSE");
|
||||
SetEvent(winmm->next);
|
||||
break;
|
||||
|
||||
case MM_WOM_DONE:
|
||||
WLog_DBG(TAG, "MM_WOM_DONE");
|
||||
lpWaveHdr = (LPWAVEHDR) dwParam1;
|
||||
free(lpWaveHdr);
|
||||
SetEvent(winmm->next);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -176,7 +174,6 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device)
|
||||
if (winmm)
|
||||
{
|
||||
rdpsnd_winmm_close(device);
|
||||
CloseHandle(winmm->next);
|
||||
free(winmm);
|
||||
}
|
||||
}
|
||||
@ -269,7 +266,6 @@ static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size
|
||||
return 0;
|
||||
}
|
||||
|
||||
WaitForSingleObject(winmm->next, INFINITE);
|
||||
return 10; /* TODO: Get real latencry in [ms] */
|
||||
}
|
||||
|
||||
@ -305,13 +301,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p
|
||||
winmm->device.Play = rdpsnd_winmm_play;
|
||||
winmm->device.Close = rdpsnd_winmm_close;
|
||||
winmm->device.Free = rdpsnd_winmm_free;
|
||||
winmm->next = CreateEventA(NULL, FALSE, FALSE, "winmm-play-event");
|
||||
|
||||
if (!winmm->next)
|
||||
{
|
||||
free(winmm);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
args = pEntryPoints->args;
|
||||
rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args);
|
||||
|
||||
@ -255,7 +255,13 @@ static UINT remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk,
|
||||
|
||||
Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */
|
||||
Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */
|
||||
remdesk->Version = versionMajor;
|
||||
|
||||
if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0))
|
||||
{
|
||||
WLog_ERR(TAG, "Unsupported protocol version %"PRId32".%"PRId32, versionMajor, versionMinor);
|
||||
}
|
||||
|
||||
remdesk->Version = versionMinor;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ struct remdesk_plugin
|
||||
UINT32 Version;
|
||||
char* ExpertBlob;
|
||||
BYTE* EncryptedPassStub;
|
||||
int EncryptedPassStubSize;
|
||||
size_t EncryptedPassStubSize;
|
||||
rdpContext* rdpcontext;
|
||||
};
|
||||
typedef struct remdesk_plugin remdeskPlugin;
|
||||
|
||||
@ -161,7 +161,7 @@ LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UI
|
||||
SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard,
|
||||
REDIR_SCARDCONTEXT* context)
|
||||
{
|
||||
SCARDCONTEXT hContext = 0;
|
||||
SCARDCONTEXT hContext = { 0 };
|
||||
|
||||
if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0))
|
||||
{
|
||||
@ -173,8 +173,6 @@ SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartca
|
||||
|
||||
if (context->cbContext)
|
||||
CopyMemory(&hContext, &(context->pbContext), context->cbContext);
|
||||
else
|
||||
ZeroMemory(&hContext, sizeof(ULONG_PTR));
|
||||
|
||||
return hContext;
|
||||
}
|
||||
|
||||
@ -21,7 +21,3 @@ define_channel("sshagent")
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_CHANNELS)
|
||||
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
|
||||
define_channel_options(NAME "sshagent" TYPE "dynamic"
|
||||
DESCRIPTION "SSH Agent Forwarding Extension"
|
||||
DESCRIPTION "SSH Agent Forwarding (experimental)"
|
||||
SPECIFICATIONS ""
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
||||
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||
define_channel_server_options(${OPTION_SERVER_DEFAULT})
|
||||
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
# Copyright 2017 Ben Cohen
|
||||
#
|
||||
# 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.
|
||||
|
||||
define_channel_server("sshagent")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
sshagent_main.c)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
|
||||
|
||||
|
||||
|
||||
target_link_libraries(${MODULE_NAME} freerdp)
|
||||
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
||||
@ -1,422 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SSH Agent Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2012-2013 Jay Sorg
|
||||
* Copyright 2012-2013 Laxmikant Rashinkar
|
||||
* Copyright 2017 Ben Cohen
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions are from OpenSSH, under the following license:
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* The authentication agent program.
|
||||
*
|
||||
* As far as I am concerned, the code I have written for this software
|
||||
* can be used freely for any purpose. Any derived versions of this
|
||||
* software must be clearly marked as such, and if the derived work is
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* xrdp-ssh-agent.c: program to forward ssh-agent protocol from xrdp session
|
||||
*
|
||||
* This performs the equivalent function of ssh-agent on a server you connect
|
||||
* to via ssh, but the ssh-agent protocol is over an RDP dynamic virtual
|
||||
* channel and not an SSH channel.
|
||||
*
|
||||
* This will print out variables to set in your environment (specifically,
|
||||
* $SSH_AUTH_SOCK) for ssh clients to find the agent's socket, then it will
|
||||
* run in the background. This is suitable to run just as you would run the
|
||||
* normal ssh-agent, e.g. in your Xsession or /etc/xrdp/startwm.sh.
|
||||
*
|
||||
* Your RDP client needs to be running a compatible client-side plugin
|
||||
* that can see a local ssh-agent.
|
||||
*
|
||||
* usage (from within an xrdp session):
|
||||
* xrdp-ssh-agent
|
||||
*
|
||||
* build instructions:
|
||||
* gcc xrdp-ssh-agent.c -o xrdp-ssh-agent -L./.libs -lxrdpapi -Wall
|
||||
*
|
||||
* protocol specification:
|
||||
* Forward data verbatim over RDP dynamic virtual channel named "sshagent"
|
||||
* between a ssh client on the xrdp server and the real ssh-agent where
|
||||
* the RDP client is running. Each connection by a separate client to
|
||||
* xrdp-ssh-agent gets a separate DVC invocation.
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include <mstsapi.h>
|
||||
#endif
|
||||
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#define _PATH_DEVNULL "/dev/null"
|
||||
|
||||
static char socket_name[PATH_MAX];
|
||||
static char socket_dir[PATH_MAX];
|
||||
static int sa_uds_fd = -1;
|
||||
static int is_going = 1;
|
||||
|
||||
|
||||
/* Make a template filename for mk[sd]temp() */
|
||||
/* This is from mktemp_proto() in misc.c from openssh */
|
||||
void
|
||||
mktemp_proto(char* s, size_t len)
|
||||
{
|
||||
const char* tmpdir;
|
||||
int r;
|
||||
|
||||
if ((tmpdir = getenv("TMPDIR")) != NULL)
|
||||
{
|
||||
r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
|
||||
|
||||
if (r > 0 && (size_t)r < len)
|
||||
return;
|
||||
}
|
||||
|
||||
r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
|
||||
|
||||
if (r < 0 || (size_t)r >= len)
|
||||
{
|
||||
fprintf(stderr, "%s: template string too short", __func__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This uses parts of main() in ssh-agent.c from openssh */
|
||||
static void
|
||||
setup_ssh_agent(struct sockaddr_un* addr)
|
||||
{
|
||||
int rc;
|
||||
/* Create private directory for agent socket */
|
||||
mktemp_proto(socket_dir, sizeof(socket_dir));
|
||||
|
||||
if (mkdtemp(socket_dir) == NULL)
|
||||
{
|
||||
perror("mkdtemp: private socket dir");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
snprintf(socket_name, sizeof(socket_name), "%s/agent.%ld", socket_dir,
|
||||
(long)getpid());
|
||||
/* Create unix domain socket */
|
||||
unlink(socket_name);
|
||||
sa_uds_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (sa_uds_fd == -1)
|
||||
{
|
||||
fprintf(stderr, "sshagent: socket creation failed");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
memset(addr, 0, sizeof(struct sockaddr_un));
|
||||
addr->sun_family = AF_UNIX;
|
||||
strncpy(addr->sun_path, socket_name, sizeof(addr->sun_path));
|
||||
addr->sun_path[sizeof(addr->sun_path) - 1] = 0;
|
||||
/* Create with privileges rw------- so other users can't access the UDS */
|
||||
mode_t umask_sav = umask(0177);
|
||||
rc = bind(sa_uds_fd, (struct sockaddr*)addr, sizeof(struct sockaddr_un));
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf(stderr, "sshagent: bind failed");
|
||||
close(sa_uds_fd);
|
||||
unlink(socket_name);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
umask(umask_sav);
|
||||
rc = listen(sa_uds_fd, /* backlog = */ 5);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
fprintf(stderr, "listen failed\n");
|
||||
close(sa_uds_fd);
|
||||
unlink(socket_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now fork: the child becomes the ssh-agent daemon and the parent prints
|
||||
* out the pid and socket name. */
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1)
|
||||
{
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
else if (pid != 0)
|
||||
{
|
||||
/* Parent */
|
||||
close(sa_uds_fd);
|
||||
printf("SSH_AUTH_SOCK=%s; export SSH_AUTH_SOCK;\n", socket_name);
|
||||
printf("SSH_AGENT_PID=%d; export SSH_AGENT_PID;\n", pid);
|
||||
printf("echo Agent pid %d;\n", pid);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Child */
|
||||
|
||||
if (setsid() == -1)
|
||||
{
|
||||
fprintf(stderr, "setsid failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
(void)chdir("/");
|
||||
int devnullfd;
|
||||
|
||||
if ((devnullfd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1)
|
||||
{
|
||||
/* XXX might close listen socket */
|
||||
(void)dup2(devnullfd, STDIN_FILENO);
|
||||
(void)dup2(devnullfd, STDOUT_FILENO);
|
||||
(void)dup2(devnullfd, STDERR_FILENO);
|
||||
|
||||
if (devnullfd > 2)
|
||||
close(devnullfd);
|
||||
}
|
||||
|
||||
/* deny core dumps, since memory contains unencrypted private keys */
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = rlim.rlim_max = 0;
|
||||
|
||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||
{
|
||||
fprintf(stderr, "setrlimit RLIMIT_CORE: %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handle_connection(int client_fd)
|
||||
{
|
||||
int rdp_fd = -1;
|
||||
int rc;
|
||||
void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION,
|
||||
"SSHAGENT",
|
||||
WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED);
|
||||
|
||||
if (channel == NULL)
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelOpenEx() failed\n");
|
||||
}
|
||||
|
||||
unsigned int retlen;
|
||||
int* retdata;
|
||||
rc = WTSVirtualChannelQuery(channel,
|
||||
WTSVirtualFileHandle,
|
||||
(void**)&retdata,
|
||||
&retlen);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelQuery() failed\n");
|
||||
}
|
||||
|
||||
if (retlen != sizeof(rdp_fd))
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %d\n",
|
||||
retlen);
|
||||
}
|
||||
|
||||
rdp_fd = *retdata;
|
||||
int client_going = 1;
|
||||
|
||||
while (client_going)
|
||||
{
|
||||
/* Wait for data from RDP or the client */
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(client_fd, &readfds);
|
||||
FD_SET(rdp_fd, &readfds);
|
||||
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(rdp_fd, &readfds))
|
||||
{
|
||||
/* Read from RDP and write to the client */
|
||||
char buffer[4096];
|
||||
unsigned int bytes_to_write;
|
||||
rc = WTSVirtualChannelRead(channel,
|
||||
/* TimeOut = */ 5000,
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
&bytes_to_write);
|
||||
|
||||
if (rc == 1)
|
||||
{
|
||||
char* pos = buffer;
|
||||
errno = 0;
|
||||
|
||||
while (bytes_to_write > 0)
|
||||
{
|
||||
int bytes_written = send(client_fd, pos, bytes_to_write, 0);
|
||||
|
||||
if (bytes_written > 0)
|
||||
{
|
||||
bytes_to_write -= bytes_written;
|
||||
pos += bytes_written;
|
||||
}
|
||||
else if (bytes_written == 0)
|
||||
{
|
||||
fprintf(stderr, "send() returned 0!\n");
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
/* Error */
|
||||
fprintf(stderr, "Error %d on recv\n", errno);
|
||||
client_going = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error */
|
||||
fprintf(stderr, "WTSVirtualChannelRead() failed: %d\n", errno);
|
||||
client_going = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(client_fd, &readfds))
|
||||
{
|
||||
/* Read from the client and write to RDP */
|
||||
char buffer[4096];
|
||||
ssize_t bytes_to_write = recv(client_fd, buffer, sizeof(buffer), 0);
|
||||
|
||||
if (bytes_to_write > 0)
|
||||
{
|
||||
char* pos = buffer;
|
||||
|
||||
while (bytes_to_write > 0)
|
||||
{
|
||||
unsigned int bytes_written;
|
||||
int rc = WTSVirtualChannelWrite(channel,
|
||||
pos,
|
||||
bytes_to_write,
|
||||
&bytes_written);
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelWrite() failed: %d\n",
|
||||
errno);
|
||||
client_going = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_to_write -= bytes_written;
|
||||
pos += bytes_written;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (bytes_to_write == 0)
|
||||
{
|
||||
/* Client has closed connection */
|
||||
client_going = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error */
|
||||
fprintf(stderr, "Error %d on recv\n", errno);
|
||||
client_going = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelClose(channel);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
/* Setup the Unix domain socket and daemon process */
|
||||
struct sockaddr_un addr;
|
||||
setup_ssh_agent(&addr);
|
||||
|
||||
/* Wait for a client to connect to the socket */
|
||||
while (is_going)
|
||||
{
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(sa_uds_fd, &readfds);
|
||||
select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
|
||||
|
||||
/* If something connected then get it...
|
||||
* (You can test this using "socat - UNIX-CONNECT:<udspath>".) */
|
||||
if (FD_ISSET(sa_uds_fd, &readfds))
|
||||
{
|
||||
socklen_t addrsize = sizeof(addr);
|
||||
int client_fd = accept(sa_uds_fd,
|
||||
(struct sockaddr*)&addr,
|
||||
&addrsize);
|
||||
handle_connection(client_fd);
|
||||
close(client_fd);
|
||||
}
|
||||
}
|
||||
|
||||
close(sa_uds_fd);
|
||||
unlink(socket_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vim: set sw=4:ts=4:et: */
|
||||
@ -151,11 +151,7 @@ static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
static inline GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp)
|
||||
#else
|
||||
static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_timestamp)
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* Convert Microsoft 100ns timestamps to Gstreamer 1ns units.
|
||||
@ -633,7 +629,8 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder)
|
||||
{
|
||||
tsmf_gstreamer_need_data,
|
||||
tsmf_gstreamer_enough_data,
|
||||
tsmf_gstreamer_seek_data
|
||||
tsmf_gstreamer_seek_data,
|
||||
{ NULL }
|
||||
};
|
||||
g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL);
|
||||
g_object_set(mdecoder->src, "is-live", FALSE, NULL);
|
||||
|
||||
@ -702,16 +702,8 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample)
|
||||
buffer_filled = FALSE;
|
||||
}
|
||||
|
||||
if (buffer_filled)
|
||||
{
|
||||
ack_anticipation_time += (sample->duration / 2 < MAX_ACK_TIME) ?
|
||||
sample->duration / 2 : MAX_ACK_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
ack_anticipation_time += (sample->duration / 2 < MAX_ACK_TIME) ?
|
||||
sample->duration / 2 : MAX_ACK_TIME;
|
||||
}
|
||||
ack_anticipation_time += (sample->duration / 2 < MAX_ACK_TIME) ?
|
||||
sample->duration / 2 : MAX_ACK_TIME;
|
||||
|
||||
switch (sample->stream->major_type)
|
||||
{
|
||||
|
||||
@ -1387,7 +1387,7 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 E
|
||||
if (iso_transfer == NULL)
|
||||
{
|
||||
WLog_ERR(TAG, "Error: libusb_alloc_transfer.");
|
||||
status = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** process URB_FUNCTION_IOSCH_TRANSFER */
|
||||
|
||||
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@ -1,7 +1,6 @@
|
||||
/*
|
||||
!/Android
|
||||
!/common
|
||||
!/DirectFB
|
||||
!/iOS
|
||||
!/Mac
|
||||
!/Sample
|
||||
|
||||
@ -26,10 +26,6 @@ if(FREERDP_VENDOR AND WITH_CLIENT)
|
||||
if(WITH_SAMPLE)
|
||||
add_subdirectory(Sample)
|
||||
endif()
|
||||
|
||||
if(WITH_DIRECTFB)
|
||||
add_subdirectory(DirectFB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_X11)
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP DirectFB Client
|
||||
#
|
||||
# Copyright 2012 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.
|
||||
|
||||
set(MODULE_NAME "dfreerdp")
|
||||
set(MODULE_PREFIX "FREERDP_CLIENT_DIRECTFB")
|
||||
|
||||
include_directories(${DIRECTFB_INCLUDE_DIRS})
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
df_event.c
|
||||
df_event.h
|
||||
df_graphics.c
|
||||
df_graphics.c
|
||||
dfreerdp.c
|
||||
dfreerdp.h)
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${DIRECTFB_LIBRARIES})
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client)
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/DirectFB")
|
||||
@ -1,4 +0,0 @@
|
||||
|
||||
set(FREERDP_CLIENT_NAME "dfreerdp")
|
||||
set(FREERDP_CLIENT_PLATFORM "DirectFB")
|
||||
set(FREERDP_CLIENT_VENDOR "FreeRDP")
|
||||
@ -1,271 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* DirectFB Event Handling
|
||||
*
|
||||
* Copyright 2011 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/input.h>
|
||||
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
|
||||
#include "df_event.h"
|
||||
|
||||
static BYTE keymap[256];
|
||||
static BYTE functionmap[128];
|
||||
|
||||
void df_keyboard_init()
|
||||
{
|
||||
ZeroMemory(keymap, sizeof(keymap));
|
||||
|
||||
/* Map DirectFB keycodes to Virtual Key Codes */
|
||||
|
||||
keymap[DIKI_A - DIKI_UNKNOWN] = VK_KEY_A;
|
||||
keymap[DIKI_B - DIKI_UNKNOWN] = VK_KEY_B;
|
||||
keymap[DIKI_C - DIKI_UNKNOWN] = VK_KEY_C;
|
||||
keymap[DIKI_D - DIKI_UNKNOWN] = VK_KEY_D;
|
||||
keymap[DIKI_E - DIKI_UNKNOWN] = VK_KEY_E;
|
||||
keymap[DIKI_F - DIKI_UNKNOWN] = VK_KEY_F;
|
||||
keymap[DIKI_G - DIKI_UNKNOWN] = VK_KEY_G;
|
||||
keymap[DIKI_H - DIKI_UNKNOWN] = VK_KEY_H;
|
||||
keymap[DIKI_I - DIKI_UNKNOWN] = VK_KEY_I;
|
||||
keymap[DIKI_J - DIKI_UNKNOWN] = VK_KEY_J;
|
||||
keymap[DIKI_K - DIKI_UNKNOWN] = VK_KEY_K;
|
||||
keymap[DIKI_L - DIKI_UNKNOWN] = VK_KEY_L;
|
||||
keymap[DIKI_M - DIKI_UNKNOWN] = VK_KEY_M;
|
||||
keymap[DIKI_N - DIKI_UNKNOWN] = VK_KEY_N;
|
||||
keymap[DIKI_O - DIKI_UNKNOWN] = VK_KEY_O;
|
||||
keymap[DIKI_P - DIKI_UNKNOWN] = VK_KEY_P;
|
||||
keymap[DIKI_Q - DIKI_UNKNOWN] = VK_KEY_Q;
|
||||
keymap[DIKI_R - DIKI_UNKNOWN] = VK_KEY_R;
|
||||
keymap[DIKI_S - DIKI_UNKNOWN] = VK_KEY_S;
|
||||
keymap[DIKI_T - DIKI_UNKNOWN] = VK_KEY_T;
|
||||
keymap[DIKI_U - DIKI_UNKNOWN] = VK_KEY_U;
|
||||
keymap[DIKI_V - DIKI_UNKNOWN] = VK_KEY_V;
|
||||
keymap[DIKI_W - DIKI_UNKNOWN] = VK_KEY_W;
|
||||
keymap[DIKI_X - DIKI_UNKNOWN] = VK_KEY_X;
|
||||
keymap[DIKI_Y - DIKI_UNKNOWN] = VK_KEY_Y;
|
||||
keymap[DIKI_Z - DIKI_UNKNOWN] = VK_KEY_Z;
|
||||
|
||||
keymap[DIKI_0 - DIKI_UNKNOWN] = VK_KEY_0;
|
||||
keymap[DIKI_1 - DIKI_UNKNOWN] = VK_KEY_1;
|
||||
keymap[DIKI_2 - DIKI_UNKNOWN] = VK_KEY_2;
|
||||
keymap[DIKI_3 - DIKI_UNKNOWN] = VK_KEY_3;
|
||||
keymap[DIKI_4 - DIKI_UNKNOWN] = VK_KEY_4;
|
||||
keymap[DIKI_5 - DIKI_UNKNOWN] = VK_KEY_5;
|
||||
keymap[DIKI_6 - DIKI_UNKNOWN] = VK_KEY_6;
|
||||
keymap[DIKI_7 - DIKI_UNKNOWN] = VK_KEY_7;
|
||||
keymap[DIKI_8 - DIKI_UNKNOWN] = VK_KEY_8;
|
||||
keymap[DIKI_9 - DIKI_UNKNOWN] = VK_KEY_9;
|
||||
|
||||
keymap[DIKI_F1 - DIKI_UNKNOWN] = VK_F1;
|
||||
keymap[DIKI_F2 - DIKI_UNKNOWN] = VK_F2;
|
||||
keymap[DIKI_F3 - DIKI_UNKNOWN] = VK_F3;
|
||||
keymap[DIKI_F4 - DIKI_UNKNOWN] = VK_F4;
|
||||
keymap[DIKI_F5 - DIKI_UNKNOWN] = VK_F5;
|
||||
keymap[DIKI_F6 - DIKI_UNKNOWN] = VK_F6;
|
||||
keymap[DIKI_F7 - DIKI_UNKNOWN] = VK_F7;
|
||||
keymap[DIKI_F8 - DIKI_UNKNOWN] = VK_F8;
|
||||
keymap[DIKI_F9 - DIKI_UNKNOWN] = VK_F9;
|
||||
keymap[DIKI_F10 - DIKI_UNKNOWN] = VK_F10;
|
||||
keymap[DIKI_F11 - DIKI_UNKNOWN] = VK_F11;
|
||||
keymap[DIKI_F12 - DIKI_UNKNOWN] = VK_F12;
|
||||
|
||||
keymap[DIKI_COMMA - DIKI_UNKNOWN] = VK_OEM_COMMA;
|
||||
keymap[DIKI_PERIOD - DIKI_UNKNOWN] = VK_OEM_PERIOD;
|
||||
keymap[DIKI_MINUS_SIGN - DIKI_UNKNOWN] = VK_OEM_MINUS;
|
||||
keymap[DIKI_EQUALS_SIGN - DIKI_UNKNOWN] = VK_OEM_PLUS;
|
||||
|
||||
keymap[DIKI_ESCAPE - DIKI_UNKNOWN] = VK_ESCAPE;
|
||||
keymap[DIKI_LEFT - DIKI_UNKNOWN] = VK_LEFT;
|
||||
keymap[DIKI_RIGHT - DIKI_UNKNOWN] = VK_RIGHT;
|
||||
keymap[DIKI_UP - DIKI_UNKNOWN] = VK_UP;
|
||||
keymap[DIKI_DOWN - DIKI_UNKNOWN] = VK_DOWN;
|
||||
keymap[DIKI_CONTROL_L - DIKI_UNKNOWN] = VK_LCONTROL;
|
||||
keymap[DIKI_CONTROL_R - DIKI_UNKNOWN] = VK_RCONTROL;
|
||||
keymap[DIKI_SHIFT_L - DIKI_UNKNOWN] = VK_LSHIFT;
|
||||
keymap[DIKI_SHIFT_R - DIKI_UNKNOWN] = VK_RSHIFT;
|
||||
keymap[DIKI_ALT_L - DIKI_UNKNOWN] = VK_LMENU;
|
||||
keymap[DIKI_ALT_R - DIKI_UNKNOWN] = VK_RMENU;
|
||||
keymap[DIKI_TAB - DIKI_UNKNOWN] = VK_TAB;
|
||||
keymap[DIKI_ENTER - DIKI_UNKNOWN] = VK_RETURN;
|
||||
keymap[DIKI_SPACE - DIKI_UNKNOWN] = VK_SPACE;
|
||||
keymap[DIKI_BACKSPACE - DIKI_UNKNOWN] = VK_BACK;
|
||||
keymap[DIKI_INSERT - DIKI_UNKNOWN] = VK_INSERT;
|
||||
keymap[DIKI_DELETE - DIKI_UNKNOWN] = VK_DELETE;
|
||||
keymap[DIKI_HOME - DIKI_UNKNOWN] = VK_HOME;
|
||||
keymap[DIKI_END - DIKI_UNKNOWN] = VK_END;
|
||||
keymap[DIKI_PAGE_UP - DIKI_UNKNOWN] = VK_PRIOR;
|
||||
keymap[DIKI_PAGE_DOWN - DIKI_UNKNOWN] = VK_NEXT;
|
||||
keymap[DIKI_CAPS_LOCK - DIKI_UNKNOWN] = VK_CAPITAL;
|
||||
keymap[DIKI_NUM_LOCK - DIKI_UNKNOWN] = VK_NUMLOCK;
|
||||
keymap[DIKI_SCROLL_LOCK - DIKI_UNKNOWN] = VK_SCROLL;
|
||||
keymap[DIKI_PRINT - DIKI_UNKNOWN] = VK_PRINT;
|
||||
keymap[DIKI_PAUSE - DIKI_UNKNOWN] = VK_PAUSE;
|
||||
keymap[DIKI_KP_DIV - DIKI_UNKNOWN] = VK_DIVIDE;
|
||||
keymap[DIKI_KP_MULT - DIKI_UNKNOWN] = VK_MULTIPLY;
|
||||
keymap[DIKI_KP_MINUS - DIKI_UNKNOWN] = VK_SUBTRACT;
|
||||
keymap[DIKI_KP_PLUS - DIKI_UNKNOWN] = VK_ADD;
|
||||
keymap[DIKI_KP_ENTER - DIKI_UNKNOWN] = VK_RETURN;
|
||||
keymap[DIKI_KP_DECIMAL - DIKI_UNKNOWN] = VK_DECIMAL;
|
||||
|
||||
keymap[DIKI_QUOTE_LEFT - DIKI_UNKNOWN] = VK_OEM_3;
|
||||
keymap[DIKI_BRACKET_LEFT - DIKI_UNKNOWN] = VK_OEM_4;
|
||||
keymap[DIKI_BRACKET_RIGHT - DIKI_UNKNOWN] = VK_OEM_6;
|
||||
keymap[DIKI_BACKSLASH - DIKI_UNKNOWN] = VK_OEM_5;
|
||||
keymap[DIKI_SEMICOLON - DIKI_UNKNOWN] = VK_OEM_1;
|
||||
keymap[DIKI_QUOTE_RIGHT - DIKI_UNKNOWN] = VK_OEM_7;
|
||||
keymap[DIKI_COMMA - DIKI_UNKNOWN] = VK_OEM_COMMA;
|
||||
keymap[DIKI_PERIOD - DIKI_UNKNOWN] = VK_OEM_PERIOD;
|
||||
keymap[DIKI_SLASH - DIKI_UNKNOWN] = VK_OEM_2;
|
||||
|
||||
keymap[DIKI_LESS_SIGN - DIKI_UNKNOWN] = 0;
|
||||
|
||||
keymap[DIKI_KP_0 - DIKI_UNKNOWN] = VK_NUMPAD0;
|
||||
keymap[DIKI_KP_1 - DIKI_UNKNOWN] = VK_NUMPAD1;
|
||||
keymap[DIKI_KP_2 - DIKI_UNKNOWN] = VK_NUMPAD2;
|
||||
keymap[DIKI_KP_3 - DIKI_UNKNOWN] = VK_NUMPAD3;
|
||||
keymap[DIKI_KP_4 - DIKI_UNKNOWN] = VK_NUMPAD4;
|
||||
keymap[DIKI_KP_5 - DIKI_UNKNOWN] = VK_NUMPAD5;
|
||||
keymap[DIKI_KP_6 - DIKI_UNKNOWN] = VK_NUMPAD6;
|
||||
keymap[DIKI_KP_7 - DIKI_UNKNOWN] = VK_NUMPAD7;
|
||||
keymap[DIKI_KP_8 - DIKI_UNKNOWN] = VK_NUMPAD8;
|
||||
keymap[DIKI_KP_9 - DIKI_UNKNOWN] = VK_NUMPAD9;
|
||||
|
||||
keymap[DIKI_META_L - DIKI_UNKNOWN] = VK_LWIN;
|
||||
keymap[DIKI_META_R - DIKI_UNKNOWN] = VK_RWIN;
|
||||
keymap[DIKI_SUPER_L - DIKI_UNKNOWN] = VK_APPS;
|
||||
|
||||
ZeroMemory(functionmap, sizeof(functionmap));
|
||||
|
||||
functionmap[DFB_FUNCTION_KEY(23) - DFB_FUNCTION_KEY(0)] = VK_HANGUL;
|
||||
functionmap[DFB_FUNCTION_KEY(24) - DFB_FUNCTION_KEY(0)] = VK_HANJA;
|
||||
|
||||
}
|
||||
|
||||
void df_send_mouse_button_event(rdpInput* input, BOOL down, UINT32 button, UINT16 x, UINT16 y)
|
||||
{
|
||||
UINT16 flags;
|
||||
|
||||
flags = (down) ? PTR_FLAGS_DOWN : 0;
|
||||
|
||||
if (button == DIBI_LEFT)
|
||||
flags |= PTR_FLAGS_BUTTON1;
|
||||
else if (button == DIBI_RIGHT)
|
||||
flags |= PTR_FLAGS_BUTTON2;
|
||||
else if (button == DIBI_MIDDLE)
|
||||
flags |= PTR_FLAGS_BUTTON3;
|
||||
|
||||
if (flags != 0)
|
||||
input->MouseEvent(input, flags, x, y);
|
||||
}
|
||||
|
||||
void df_send_mouse_motion_event(rdpInput* input, UINT16 x, UINT16 y)
|
||||
{
|
||||
input->MouseEvent(input, PTR_FLAGS_MOVE, x, y);
|
||||
}
|
||||
|
||||
void df_send_mouse_wheel_event(rdpInput* input, INT16 axisrel, UINT16 x, UINT16 y)
|
||||
{
|
||||
UINT16 flags = PTR_FLAGS_WHEEL;
|
||||
|
||||
if (axisrel < 0)
|
||||
flags |= 0x0078;
|
||||
else
|
||||
flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
|
||||
|
||||
input->MouseEvent(input, flags, x, y);
|
||||
}
|
||||
|
||||
void df_send_keyboard_event(rdpInput* input, BOOL down, BYTE keycode, BYTE function)
|
||||
{
|
||||
DWORD scancode = 0;
|
||||
BYTE vkcode = VK_NONE;
|
||||
|
||||
if (keycode)
|
||||
vkcode = keymap[keycode];
|
||||
else if (function)
|
||||
vkcode = functionmap[function];
|
||||
|
||||
if (vkcode != VK_NONE)
|
||||
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, input->context->settings->KeyboardType);
|
||||
|
||||
if (scancode)
|
||||
freerdp_input_send_keyboard_event_ex(input, down, scancode);
|
||||
}
|
||||
|
||||
BOOL df_event_process(freerdp* instance, DFBEvent* event)
|
||||
{
|
||||
int flags;
|
||||
rdpGdi* gdi;
|
||||
dfInfo* dfi;
|
||||
int pointer_x;
|
||||
int pointer_y;
|
||||
DFBInputEvent* input_event;
|
||||
|
||||
gdi = instance->context->gdi;
|
||||
dfi = ((dfContext*) instance->context)->dfi;
|
||||
|
||||
dfi->layer->GetCursorPosition(dfi->layer, &pointer_x, &pointer_y);
|
||||
|
||||
if (event->clazz == DFEC_INPUT)
|
||||
{
|
||||
flags = 0;
|
||||
input_event = (DFBInputEvent*) event;
|
||||
|
||||
switch (input_event->type)
|
||||
{
|
||||
case DIET_AXISMOTION:
|
||||
|
||||
if (pointer_x > (gdi->width - 1))
|
||||
pointer_x = gdi->width - 1;
|
||||
|
||||
if (pointer_y > (gdi->height - 1))
|
||||
pointer_y = gdi->height - 1;
|
||||
|
||||
if (input_event->axis == DIAI_Z)
|
||||
{
|
||||
df_send_mouse_wheel_event(instance->input, input_event->axisrel, pointer_x, pointer_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
df_send_mouse_motion_event(instance->input, pointer_x, pointer_y);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIET_BUTTONPRESS:
|
||||
df_send_mouse_button_event(instance->input, TRUE, input_event->button, pointer_x, pointer_y);
|
||||
break;
|
||||
|
||||
case DIET_BUTTONRELEASE:
|
||||
df_send_mouse_button_event(instance->input, FALSE, input_event->button, pointer_x, pointer_y);
|
||||
break;
|
||||
|
||||
case DIET_KEYPRESS:
|
||||
df_send_keyboard_event(instance->input, TRUE, input_event->key_id - DIKI_UNKNOWN, input_event->key_symbol - DFB_FUNCTION_KEY(0));
|
||||
break;
|
||||
|
||||
case DIET_KEYRELEASE:
|
||||
df_send_keyboard_event(instance->input, FALSE, input_event->key_id - DIKI_UNKNOWN, input_event->key_symbol - DFB_FUNCTION_KEY(0));
|
||||
break;
|
||||
|
||||
case DIET_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -1,139 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* DirectFB Graphical Objects
|
||||
*
|
||||
* Copyright 2011 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 "df_graphics.h"
|
||||
|
||||
/* Pointer Class */
|
||||
|
||||
void df_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
dfInfo* dfi;
|
||||
DFBResult result;
|
||||
dfPointer* df_pointer;
|
||||
DFBSurfaceDescription dsc;
|
||||
|
||||
dfi = ((dfContext*) context)->dfi;
|
||||
df_pointer = (dfPointer*) pointer;
|
||||
|
||||
dsc.flags = DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
|
||||
dsc.caps = DSCAPS_SYSTEMONLY;
|
||||
dsc.width = pointer->width;
|
||||
dsc.height = pointer->height;
|
||||
dsc.pixelformat = DSPF_ARGB;
|
||||
|
||||
result = dfi->dfb->CreateSurface(dfi->dfb, &dsc, &(df_pointer->surface));
|
||||
|
||||
if (result == DFB_OK)
|
||||
{
|
||||
int pitch;
|
||||
BYTE* point = NULL;
|
||||
|
||||
df_pointer->xhot = pointer->xPos;
|
||||
df_pointer->yhot = pointer->yPos;
|
||||
|
||||
result = df_pointer->surface->Lock(df_pointer->surface,
|
||||
DSLF_WRITE, (void**) &point, &pitch);
|
||||
|
||||
if (result != DFB_OK)
|
||||
{
|
||||
DirectFBErrorFatal("Error while creating pointer surface", result);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0))
|
||||
{
|
||||
freerdp_alpha_cursor_convert(point, pointer->xorMaskData, pointer->andMaskData,
|
||||
pointer->width, pointer->height, pointer->xorBpp, dfi->clrconv);
|
||||
}
|
||||
|
||||
if (pointer->xorBpp > 24)
|
||||
{
|
||||
freerdp_image_swap_color_order(point, pointer->width, pointer->height);
|
||||
}
|
||||
|
||||
df_pointer->surface->Unlock(df_pointer->surface);
|
||||
}
|
||||
}
|
||||
|
||||
void df_Pointer_Free(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
dfPointer* df_pointer = (dfPointer*) pointer;
|
||||
df_pointer->surface->Release(df_pointer->surface);
|
||||
}
|
||||
|
||||
void df_Pointer_Set(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
dfInfo* dfi;
|
||||
DFBResult result;
|
||||
dfPointer* df_pointer;
|
||||
|
||||
dfi = ((dfContext*) context)->dfi;
|
||||
df_pointer = (dfPointer*) pointer;
|
||||
|
||||
dfi->layer->SetCooperativeLevel(dfi->layer, DLSCL_ADMINISTRATIVE);
|
||||
|
||||
dfi->layer->SetCursorOpacity(dfi->layer, df_pointer ? 255: 0);
|
||||
|
||||
if(df_pointer != NULL)
|
||||
{
|
||||
result = dfi->layer->SetCursorShape(dfi->layer,
|
||||
df_pointer->surface, df_pointer->xhot, df_pointer->yhot);
|
||||
|
||||
if (result != DFB_OK)
|
||||
{
|
||||
DirectFBErrorFatal("SetCursorShape Error", result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dfi->layer->SetCooperativeLevel(dfi->layer, DLSCL_SHARED);
|
||||
}
|
||||
|
||||
void df_Pointer_SetNull(rdpContext* context)
|
||||
{
|
||||
df_Pointer_Set(context, NULL);
|
||||
}
|
||||
|
||||
void df_Pointer_SetDefault(rdpContext* context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* Graphics Module */
|
||||
|
||||
void df_register_graphics(rdpGraphics* graphics)
|
||||
{
|
||||
rdpPointer* pointer;
|
||||
|
||||
pointer = (rdpPointer*) malloc(sizeof(rdpPointer));
|
||||
ZeroMemory(pointer, sizeof(rdpPointer));
|
||||
pointer->size = sizeof(dfPointer);
|
||||
|
||||
pointer->New = df_Pointer_New;
|
||||
pointer->Free = df_Pointer_Free;
|
||||
pointer->Set = df_Pointer_Set;
|
||||
pointer->SetNull = df_Pointer_SetNull;
|
||||
pointer->SetDefault = df_Pointer_SetDefault;
|
||||
|
||||
graphics_register_pointer(graphics, pointer);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
@ -1,469 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* DirectFB Client
|
||||
*
|
||||
* Copyright 2011 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 <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/event.h>
|
||||
|
||||
#include <freerdp/client/file.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#include "df_event.h"
|
||||
#include "df_graphics.h"
|
||||
|
||||
#include "dfreerdp.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("directFB")
|
||||
|
||||
static HANDLE g_sem;
|
||||
static int g_thread_count = 0;
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
freerdp* instance;
|
||||
};
|
||||
|
||||
BOOL df_context_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void df_context_free(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void df_begin_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
}
|
||||
|
||||
void df_end_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
dfInfo* dfi;
|
||||
gdi = context->gdi;
|
||||
dfi = ((dfContext*) context)->dfi;
|
||||
|
||||
if (gdi->primary->hdc->hwnd->invalid->null)
|
||||
return;
|
||||
|
||||
#if 1
|
||||
dfi->update_rect.x = gdi->primary->hdc->hwnd->invalid->x;
|
||||
dfi->update_rect.y = gdi->primary->hdc->hwnd->invalid->y;
|
||||
dfi->update_rect.w = gdi->primary->hdc->hwnd->invalid->w;
|
||||
dfi->update_rect.h = gdi->primary->hdc->hwnd->invalid->h;
|
||||
#else
|
||||
dfi->update_rect.x = 0;
|
||||
dfi->update_rect.y = 0;
|
||||
dfi->update_rect.w = gdi->width;
|
||||
dfi->update_rect.h = gdi->height;
|
||||
#endif
|
||||
dfi->primary->Blit(dfi->primary, dfi->surface, &(dfi->update_rect),
|
||||
dfi->update_rect.x, dfi->update_rect.y);
|
||||
}
|
||||
|
||||
BOOL df_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds,
|
||||
int* wcount)
|
||||
{
|
||||
dfInfo* dfi;
|
||||
dfi = ((dfContext*) instance->context)->dfi;
|
||||
rfds[*rcount] = (void*)(long)(dfi->read_fds);
|
||||
(*rcount)++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL df_check_fds(freerdp* instance, fd_set* set)
|
||||
{
|
||||
dfInfo* dfi;
|
||||
dfi = ((dfContext*) instance->context)->dfi;
|
||||
|
||||
if (!FD_ISSET(dfi->read_fds, set))
|
||||
return TRUE;
|
||||
|
||||
if (read(dfi->read_fds, &(dfi->event), sizeof(dfi->event)) > 0)
|
||||
df_event_process(instance, &(dfi->event));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL df_pre_connect(freerdp* instance)
|
||||
{
|
||||
dfInfo* dfi;
|
||||
BOOL bitmap_cache;
|
||||
dfContext* context;
|
||||
rdpSettings* settings;
|
||||
dfi = (dfInfo*) malloc(sizeof(dfInfo));
|
||||
ZeroMemory(dfi, sizeof(dfInfo));
|
||||
context = ((dfContext*) instance->context);
|
||||
context->dfi = dfi;
|
||||
settings = instance->settings;
|
||||
bitmap_cache = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEMBLT_INDEX] = bitmap_cache;
|
||||
settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
|
||||
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
||||
dfi->clrconv = (CLRCONV*) malloc(sizeof(CLRCONV));
|
||||
ZeroMemory(dfi->clrconv, sizeof(CLRCONV));
|
||||
dfi->clrconv->alpha = 1;
|
||||
dfi->clrconv->invert = 0;
|
||||
dfi->clrconv->rgb555 = 0;
|
||||
dfi->clrconv->palette = (rdpPalette*) malloc(sizeof(rdpPalette));
|
||||
ZeroMemory(dfi->clrconv->palette, sizeof(rdpPalette));
|
||||
return (instance->context->cache = cache_new(instance->settings)) != NULL;
|
||||
}
|
||||
|
||||
BOOL df_post_connect(freerdp* instance)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
dfInfo* dfi;
|
||||
dfContext* context;
|
||||
context = ((dfContext*) instance->context);
|
||||
dfi = context->dfi;
|
||||
|
||||
if (!gdi_init(instance, CLRCONV_ALPHA | CLRCONV_INVERT | CLRBUF_16BPP |
|
||||
CLRBUF_32BPP, NULL))
|
||||
return FALSE;
|
||||
|
||||
gdi = instance->context->gdi;
|
||||
dfi->err = DirectFBCreate(&(dfi->dfb));
|
||||
dfi->dsc.flags = DSDESC_CAPS;
|
||||
dfi->dsc.caps = DSCAPS_PRIMARY;
|
||||
dfi->err = dfi->dfb->CreateSurface(dfi->dfb, &(dfi->dsc), &(dfi->primary));
|
||||
dfi->err = dfi->primary->GetSize(dfi->primary, &(gdi->width), &(gdi->height));
|
||||
dfi->dfb->SetVideoMode(dfi->dfb, gdi->width, gdi->height, gdi->dstBpp);
|
||||
dfi->dfb->CreateInputEventBuffer(dfi->dfb, DICAPS_ALL, DFB_TRUE,
|
||||
&(dfi->event_buffer));
|
||||
dfi->event_buffer->CreateFileDescriptor(dfi->event_buffer, &(dfi->read_fds));
|
||||
dfi->dfb->GetDisplayLayer(dfi->dfb, 0, &(dfi->layer));
|
||||
dfi->layer->EnableCursor(dfi->layer, 1);
|
||||
dfi->dsc.flags = DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT |
|
||||
DSDESC_PREALLOCATED | DSDESC_PIXELFORMAT;
|
||||
dfi->dsc.caps = DSCAPS_SYSTEMONLY;
|
||||
dfi->dsc.width = gdi->width;
|
||||
dfi->dsc.height = gdi->height;
|
||||
|
||||
if (gdi->dstBpp == 32 || gdi->dstBpp == 24)
|
||||
dfi->dsc.pixelformat = DSPF_AiRGB;
|
||||
else if (gdi->dstBpp == 16 || gdi->dstBpp == 15)
|
||||
dfi->dsc.pixelformat = DSPF_RGB16;
|
||||
else if (gdi->dstBpp == 8)
|
||||
dfi->dsc.pixelformat = DSPF_RGB332;
|
||||
else
|
||||
dfi->dsc.pixelformat = DSPF_AiRGB;
|
||||
|
||||
dfi->dsc.preallocated[0].data = gdi->primary_buffer;
|
||||
dfi->dsc.preallocated[0].pitch = gdi->width * gdi->bytesPerPixel;
|
||||
dfi->dfb->CreateSurface(dfi->dfb, &(dfi->dsc), &(dfi->surface));
|
||||
instance->update->BeginPaint = df_begin_paint;
|
||||
instance->update->EndPaint = df_end_paint;
|
||||
df_keyboard_init();
|
||||
df_register_graphics(instance->context->graphics);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL df_verify_certificate(freerdp* instance, char* subject, char* issuer,
|
||||
char* fingerprint)
|
||||
{
|
||||
char answer;
|
||||
WLog_INFO(TAG, "Certificate details:");
|
||||
WLog_INFO(TAG, "\tSubject: %s", subject);
|
||||
WLog_INFO(TAG, "\tIssuer: %s", issuer);
|
||||
WLog_INFO(TAG, "\tThumbprint: %s", fingerprint);
|
||||
WLog_INFO(TAG,
|
||||
"The above X.509 certificate could not be verified, possibly because you do not have "
|
||||
"the CA certificate in your certificate store, or the certificate has expired. "
|
||||
"Please look at the OpenSSL documentation on how to add a private CA to the store.");
|
||||
|
||||
while (1)
|
||||
{
|
||||
WLog_INFO(TAG, "Do you trust the above certificate? (Y/N) ");
|
||||
answer = fgetc(stdin);
|
||||
|
||||
if (answer == 'y' || answer == 'Y')
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else if (answer == 'n' || answer == 'N')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int df_receive_channel_data(freerdp* instance, UINT16 channelId,
|
||||
BYTE* data, int size, int flags, int total_size)
|
||||
{
|
||||
return freerdp_channels_data(instance, channelId, data, size, flags,
|
||||
total_size);
|
||||
}
|
||||
|
||||
static void df_process_cb_monitor_ready_event(rdpChannels* channels,
|
||||
freerdp* instance)
|
||||
{
|
||||
wMessage* event;
|
||||
RDP_CB_FORMAT_LIST_EVENT* format_list_event;
|
||||
event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL,
|
||||
NULL);
|
||||
format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event;
|
||||
format_list_event->num_formats = 0;
|
||||
freerdp_channels_send_event(channels, event);
|
||||
}
|
||||
|
||||
static void df_process_channel_event(rdpChannels* channels, freerdp* instance)
|
||||
{
|
||||
wMessage* event;
|
||||
event = freerdp_channels_pop_event(channels);
|
||||
|
||||
if (event)
|
||||
{
|
||||
switch (GetMessageType(event->id))
|
||||
{
|
||||
case CliprdrChannel_MonitorReady:
|
||||
df_process_cb_monitor_ready_event(channels, instance);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "df_process_channel_event: unknown event type %"PRIu32"",
|
||||
GetMessageType(event->id));
|
||||
break;
|
||||
}
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
static void df_free(dfInfo* dfi)
|
||||
{
|
||||
dfi->dfb->Release(dfi->dfb);
|
||||
free(dfi);
|
||||
}
|
||||
|
||||
int dfreerdp_run(freerdp* instance)
|
||||
{
|
||||
int i;
|
||||
int fds;
|
||||
int max_fds;
|
||||
int rcount;
|
||||
int wcount;
|
||||
void* rfds[32];
|
||||
void* wfds[32];
|
||||
fd_set rfds_set;
|
||||
fd_set wfds_set;
|
||||
dfInfo* dfi;
|
||||
dfContext* context;
|
||||
rdpChannels* channels;
|
||||
ZeroMemory(rfds, sizeof(rfds));
|
||||
ZeroMemory(wfds, sizeof(wfds));
|
||||
|
||||
if (!freerdp_connect(instance))
|
||||
return 0;
|
||||
|
||||
context = (dfContext*) instance->context;
|
||||
dfi = context->dfi;
|
||||
channels = instance->context->channels;
|
||||
|
||||
while (1)
|
||||
{
|
||||
rcount = 0;
|
||||
wcount = 0;
|
||||
|
||||
if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds,
|
||||
&wcount) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get channel manager file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (df_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to get dfreerdp file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
max_fds = 0;
|
||||
FD_ZERO(&rfds_set);
|
||||
FD_ZERO(&wfds_set);
|
||||
|
||||
for (i = 0; i < rcount; i++)
|
||||
{
|
||||
fds = (int)(long)(rfds[i]);
|
||||
|
||||
if (fds > max_fds)
|
||||
max_fds = fds;
|
||||
|
||||
FD_SET(fds, &rfds_set);
|
||||
}
|
||||
|
||||
if (max_fds == 0)
|
||||
break;
|
||||
|
||||
if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1)
|
||||
{
|
||||
/* these are not really errors */
|
||||
if (!((errno == EAGAIN) ||
|
||||
(errno == EWOULDBLOCK) ||
|
||||
(errno == EINPROGRESS) ||
|
||||
(errno == EINTR))) /* signal occurred */
|
||||
{
|
||||
WLog_ERR(TAG, "dfreerdp_run: select failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (freerdp_check_fds(instance) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (df_check_fds(instance, &rfds_set) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check dfreerdp file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
if (freerdp_channels_check_fds(channels, instance) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to check channel manager file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
df_process_channel_event(channels, instance);
|
||||
}
|
||||
|
||||
freerdp_disconnect(instance);
|
||||
df_free(dfi);
|
||||
gdi_free(instance);
|
||||
freerdp_free(instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* thread_func(void* param)
|
||||
{
|
||||
struct thread_data* data;
|
||||
data = (struct thread_data*) param;
|
||||
dfreerdp_run(data->instance);
|
||||
free(data);
|
||||
pthread_detach(pthread_self());
|
||||
g_thread_count--;
|
||||
|
||||
if (g_thread_count < 1)
|
||||
ReleaseSemaphore(g_sem, 1, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int status;
|
||||
pthread_t thread;
|
||||
freerdp* instance;
|
||||
dfContext* context;
|
||||
rdpChannels* channels;
|
||||
struct thread_data* data;
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
if (!(g_sem = CreateSemaphore(NULL, 0, 1, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create semaphore");
|
||||
return 1;
|
||||
}
|
||||
|
||||
instance = freerdp_new();
|
||||
instance->PreConnect = df_pre_connect;
|
||||
instance->PostConnect = df_post_connect;
|
||||
instance->VerifyCertificate = df_verify_certificate;
|
||||
instance->ReceiveChannelData = df_receive_channel_data;
|
||||
instance->ContextSize = sizeof(dfContext);
|
||||
instance->ContextNew = df_context_new;
|
||||
instance->ContextFree = df_context_free;
|
||||
|
||||
if (!freerdp_context_new(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create FreeRDP context");
|
||||
return 1;
|
||||
}
|
||||
|
||||
context = (dfContext*) instance->context;
|
||||
channels = instance->context->channels;
|
||||
DirectFBInit(&argc, &argv);
|
||||
instance->context->argc = argc;
|
||||
instance->context->argv = argv;
|
||||
status = freerdp_client_settings_parse_command_line(instance->settings, argc,
|
||||
argv, FALSE);
|
||||
|
||||
if (status < 0)
|
||||
return 0;
|
||||
|
||||
if (!freerdp_client_load_addins(instance->context->channels,
|
||||
instance->settings))
|
||||
return -1;
|
||||
|
||||
data = (struct thread_data*) malloc(sizeof(struct thread_data));
|
||||
ZeroMemory(data, sizeof(sizeof(struct thread_data)));
|
||||
data->instance = instance;
|
||||
g_thread_count++;
|
||||
pthread_create(&thread, 0, thread_func, data);
|
||||
|
||||
while (g_thread_count > 0)
|
||||
{
|
||||
WaitForSingleObject(g_sem, INFINITE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* DirectFB Client
|
||||
*
|
||||
* Copyright 2011 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_CLIENT_DF_FREERDP_H
|
||||
#define FREERDP_CLIENT_DF_FREERDP_H
|
||||
|
||||
#include "config.h"
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/graphics.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <directfb.h>
|
||||
|
||||
typedef struct df_info dfInfo;
|
||||
|
||||
struct df_context
|
||||
{
|
||||
rdpContext _p;
|
||||
|
||||
dfInfo* dfi;
|
||||
rdpSettings* settings;
|
||||
};
|
||||
typedef struct df_context dfContext;
|
||||
|
||||
struct df_pointer
|
||||
{
|
||||
rdpPointer pointer;
|
||||
IDirectFBSurface* surface;
|
||||
UINT32 xhot;
|
||||
UINT32 yhot;
|
||||
};
|
||||
typedef struct df_pointer dfPointer;
|
||||
|
||||
struct df_info
|
||||
{
|
||||
int read_fds;
|
||||
DFBResult err;
|
||||
IDirectFB* dfb;
|
||||
DFBEvent event;
|
||||
HCLRCONV clrconv;
|
||||
DFBRectangle update_rect;
|
||||
DFBSurfaceDescription dsc;
|
||||
IDirectFBSurface* primary;
|
||||
IDirectFBSurface* surface;
|
||||
IDirectFBDisplayLayer* layer;
|
||||
IDirectFBEventBuffer* event_buffer;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CLIENT_DF_FREERDP_H */
|
||||
@ -19,7 +19,10 @@ set(MODULE_NAME "sfreerdp")
|
||||
set(MODULE_PREFIX "FREERDP_CLIENT_SAMPLE")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
freerdp.c)
|
||||
tf_channels.c
|
||||
tf_channels.h
|
||||
tf_freerdp.h
|
||||
tf_freerdp.c)
|
||||
|
||||
# On windows create dll version information.
|
||||
# Vendor, product and year are already set in top level CMakeLists.txt
|
||||
|
||||
@ -1,212 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Test UI
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/client/file.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#define TAG CLIENT_TAG("sample")
|
||||
|
||||
struct tf_context
|
||||
{
|
||||
rdpContext _p;
|
||||
};
|
||||
typedef struct tf_context tfContext;
|
||||
|
||||
static BOOL tf_context_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void tf_context_free(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
static BOOL tf_begin_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tf_end_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
if (gdi->primary->hdc->hwnd->invalid->null)
|
||||
return TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tf_pre_connect(freerdp* instance)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
settings = instance->settings;
|
||||
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEMBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEM3BLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tf_post_connect(freerdp* instance)
|
||||
{
|
||||
if (!gdi_init(instance, PIXEL_FORMAT_XRGB32))
|
||||
return FALSE;
|
||||
|
||||
instance->update->BeginPaint = tf_begin_paint;
|
||||
instance->update->EndPaint = tf_end_paint;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DWORD WINAPI tf_client_thread_proc(LPVOID arg)
|
||||
{
|
||||
freerdp* instance = (freerdp*)arg;
|
||||
DWORD nCount;
|
||||
DWORD status;
|
||||
HANDLE handles[64];
|
||||
|
||||
if (!freerdp_connect(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "connection failure");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!freerdp_shall_disconnect(instance))
|
||||
{
|
||||
nCount = freerdp_get_event_handles(instance->context, &handles[0], 64);
|
||||
|
||||
if (nCount == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
|
||||
|
||||
if (status == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__,
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!freerdp_check_event_handles(instance->context))
|
||||
{
|
||||
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP event handles");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_disconnect(instance);
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int status;
|
||||
HANDLE thread;
|
||||
freerdp* instance;
|
||||
instance = freerdp_new();
|
||||
|
||||
if (!instance)
|
||||
{
|
||||
WLog_ERR(TAG, "Couldn't create instance");
|
||||
return 1;
|
||||
}
|
||||
|
||||
instance->PreConnect = tf_pre_connect;
|
||||
instance->PostConnect = tf_post_connect;
|
||||
instance->ContextSize = sizeof(tfContext);
|
||||
instance->ContextNew = tf_context_new;
|
||||
instance->ContextFree = tf_context_free;
|
||||
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
|
||||
|
||||
if (!freerdp_context_new(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "Couldn't create context");
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = freerdp_client_settings_parse_command_line(instance->settings, argc,
|
||||
argv, FALSE);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!freerdp_client_load_addins(instance->context->channels,
|
||||
instance->settings))
|
||||
return -1;
|
||||
|
||||
if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to create client thread");
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
}
|
||||
|
||||
freerdp_context_free(instance);
|
||||
freerdp_free(instance);
|
||||
return 0;
|
||||
}
|
||||
127
client/Sample/tf_channels.c
Normal file
127
client/Sample/tf_channels.c
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Sample Client Channels
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <freerdp/gdi/gfx.h>
|
||||
|
||||
#include <freerdp/client/rdpei.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
#include <freerdp/client/rail.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/client/encomsp.h>
|
||||
|
||||
#include "tf_channels.h"
|
||||
#include "tf_freerdp.h"
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT tf_encomsp_participant_created(EncomspClientContext* context,
|
||||
ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated)
|
||||
{
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void tf_encomsp_init(tfContext* tf, EncomspClientContext* encomsp)
|
||||
{
|
||||
tf->encomsp = encomsp;
|
||||
encomsp->custom = (void*) tf;
|
||||
encomsp->ParticipantCreated = tf_encomsp_participant_created;
|
||||
}
|
||||
|
||||
static void tf_encomsp_uninit(tfContext* tf, EncomspClientContext* encomsp)
|
||||
{
|
||||
if (encomsp)
|
||||
{
|
||||
encomsp->custom = NULL;
|
||||
encomsp->ParticipantCreated = NULL;
|
||||
}
|
||||
|
||||
if (tf)
|
||||
tf->encomsp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void tf_OnChannelConnectedEventHandler(void* context,
|
||||
ChannelConnectedEventArgs* e)
|
||||
{
|
||||
tfContext* tf = (tfContext*) context;
|
||||
rdpSettings* settings;
|
||||
settings = tf->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
tf->rdpei = (RdpeiClientContext*) e->pInterface;
|
||||
}
|
||||
else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
gdi_graphics_pipeline_init(tf->context.gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
tf_encomsp_init(tf, (EncomspClientContext*) e->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
void tf_OnChannelDisconnectedEventHandler(void* context,
|
||||
ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
tfContext* tf = (tfContext*) context;
|
||||
rdpSettings* settings;
|
||||
settings = tf->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
tf->rdpei = NULL;
|
||||
}
|
||||
else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
gdi_graphics_pipeline_uninit(tf->context.gdi,
|
||||
(RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
tf_encomsp_uninit(tf, (EncomspClientContext*) e->pInterface);
|
||||
}
|
||||
}
|
||||
37
client/Sample/tf_channels.h
Normal file
37
client/Sample/tf_channels.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Sample Client Channels
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CLIENT_SAMPLE_CHANNELS_H
|
||||
#define FREERDP_CLIENT_SAMPLE_CHANNELS_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
|
||||
int tf_on_channel_connected(freerdp* instance, const char* name,
|
||||
void* pInterface);
|
||||
int tf_on_channel_disconnected(freerdp* instance, const char* name,
|
||||
void* pInterface);
|
||||
|
||||
void tf_OnChannelConnectedEventHandler(void* context,
|
||||
ChannelConnectedEventArgs* e);
|
||||
void tf_OnChannelDisconnectedEventHandler(void* context,
|
||||
ChannelDisconnectedEventArgs* e);
|
||||
|
||||
#endif /* FREERDP_CLIENT_SAMPLE_CHANNELS_H */
|
||||
339
client/Sample/tf_freerdp.c
Normal file
339
client/Sample/tf_freerdp.c
Normal file
@ -0,0 +1,339 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP Test UI
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2016,2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2016,2018 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/utils/signal.h>
|
||||
|
||||
#include <freerdp/client/file.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "tf_channels.h"
|
||||
#include "tf_freerdp.h"
|
||||
|
||||
#define TAG CLIENT_TAG("sample")
|
||||
|
||||
/* This function is called whenever a new frame starts.
|
||||
* It can be used to reset invalidated areas. */
|
||||
static BOOL tf_begin_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
gdi->primary->hdc->hwnd->invalid->null = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called when the library completed composing a new
|
||||
* frame. Read out the changed areas and blit them to your output device.
|
||||
* The image buffer will have the format specified by gdi_init
|
||||
*/
|
||||
static BOOL tf_end_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi = context->gdi;
|
||||
|
||||
if (gdi->primary->hdc->hwnd->invalid->null)
|
||||
return TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called to output a System BEEP */
|
||||
static BOOL tf_play_sound(rdpContext* context,
|
||||
const PLAY_SOUND_UPDATE* play_sound)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called to update the keyboard indocator LED */
|
||||
static BOOL tf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
|
||||
{
|
||||
/* TODO: Set local keyboard indicator LED status */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called to set the IME state */
|
||||
static BOOL tf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
|
||||
UINT32 imeConvMode)
|
||||
{
|
||||
if (!context)
|
||||
return FALSE;
|
||||
|
||||
WLog_WARN(TAG,
|
||||
"KeyboardSetImeStatus(unitId=%04"PRIx16", imeState=%08"PRIx32", imeConvMode=%08"PRIx32") ignored",
|
||||
imeId, imeState, imeConvMode);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Called before a connection is established.
|
||||
* Set all configuration options to support and load channels here. */
|
||||
static BOOL tf_pre_connect(freerdp* instance)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
settings = instance->settings;
|
||||
/* Optional OS identifier sent to server */
|
||||
settings->OsMajorType = OSMAJORTYPE_UNIX;
|
||||
settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER;
|
||||
/* settings->OrderSupport is initialized at this point.
|
||||
* Only override it if you plan to implement custom order
|
||||
* callbacks or deactiveate certain features. */
|
||||
/* Register the channel listeners.
|
||||
* They are required to set up / tear down channels if they are loaded. */
|
||||
PubSub_SubscribeChannelConnected(instance->context->pubSub,
|
||||
tf_OnChannelConnectedEventHandler);
|
||||
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
|
||||
tf_OnChannelDisconnectedEventHandler);
|
||||
|
||||
/* Load all required plugins / channels / libraries specified by current
|
||||
* settings. */
|
||||
if (!freerdp_client_load_addins(instance->context->channels,
|
||||
instance->settings))
|
||||
return FALSE;
|
||||
|
||||
/* TODO: Any code your client requires */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Called after a RDP connection was successfully established.
|
||||
* Settings might have changed during negociation of client / server feature
|
||||
* support.
|
||||
*
|
||||
* Set up local framebuffers and paing callbacks.
|
||||
* If required, register pointer callbacks to change the local mouse cursor
|
||||
* when hovering over the RDP window
|
||||
*/
|
||||
static BOOL tf_post_connect(freerdp* instance)
|
||||
{
|
||||
if (!gdi_init(instance, PIXEL_FORMAT_XRGB32))
|
||||
return FALSE;
|
||||
|
||||
instance->update->BeginPaint = tf_begin_paint;
|
||||
instance->update->EndPaint = tf_end_paint;
|
||||
instance->update->PlaySound = tf_play_sound;
|
||||
instance->update->SetKeyboardIndicators = tf_keyboard_set_indicators;
|
||||
instance->update->SetKeyboardImeStatus = tf_keyboard_set_ime_status;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called whether a session ends by failure or success.
|
||||
* Clean up everything allocated by pre_connect and post_connect.
|
||||
*/
|
||||
static void tf_post_disconnect(freerdp* instance)
|
||||
{
|
||||
tfContext* context;
|
||||
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
if (!instance->context)
|
||||
return;
|
||||
|
||||
context = (tfContext*) instance->context;
|
||||
PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
|
||||
tf_OnChannelConnectedEventHandler);
|
||||
PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
|
||||
tf_OnChannelDisconnectedEventHandler);
|
||||
gdi_free(instance);
|
||||
/* TODO : Clean up custom stuff */
|
||||
}
|
||||
|
||||
/* RDP main loop.
|
||||
* Connects RDP, loops while running and handles event and dispatch, cleans up
|
||||
* after the connection ends. */
|
||||
static DWORD WINAPI tf_client_thread_proc(LPVOID arg)
|
||||
{
|
||||
freerdp* instance = (freerdp*)arg;
|
||||
DWORD nCount;
|
||||
DWORD status;
|
||||
HANDLE handles[64];
|
||||
|
||||
if (!freerdp_connect(instance))
|
||||
{
|
||||
WLog_ERR(TAG, "connection failure");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!freerdp_shall_disconnect(instance))
|
||||
{
|
||||
nCount = freerdp_get_event_handles(instance->context, &handles[0], 64);
|
||||
|
||||
if (nCount == 0)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: freerdp_get_event_handles failed", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
status = WaitForMultipleObjects(nCount, handles, FALSE, 100);
|
||||
|
||||
if (status == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: WaitForMultipleObjects failed with %"PRIu32"", __FUNCTION__,
|
||||
status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!freerdp_check_event_handles(instance->context))
|
||||
{
|
||||
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
|
||||
WLog_ERR(TAG, "Failed to check FreeRDP event handles");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freerdp_disconnect(instance);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Optional global initializer.
|
||||
* Here we just register a signal handler to print out stack traces
|
||||
* if available. */
|
||||
static BOOL tf_client_global_init(void)
|
||||
{
|
||||
if (freerdp_handle_signals() != 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Optional global tear down */
|
||||
static void tf_client_global_uninit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int tf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
|
||||
{
|
||||
tfContext* tf;
|
||||
const char* str_data = freerdp_get_logon_error_info_data(data);
|
||||
const char* str_type = freerdp_get_logon_error_info_type(type);
|
||||
|
||||
if (!instance || !instance->context)
|
||||
return -1;
|
||||
|
||||
tf = (tfContext*) instance->context;
|
||||
WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL tf_client_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
tfContext* tf = (tfContext*) context;
|
||||
|
||||
if (!instance || !context)
|
||||
return FALSE;
|
||||
|
||||
instance->PreConnect = tf_pre_connect;
|
||||
instance->PostConnect = tf_post_connect;
|
||||
instance->PostDisconnect = tf_post_disconnect;
|
||||
instance->Authenticate = client_cli_authenticate;
|
||||
instance->GatewayAuthenticate = client_cli_gw_authenticate;
|
||||
instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
|
||||
instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
|
||||
instance->LogonErrorInfo = tf_logon_error_info;
|
||||
/* TODO: Client display set up */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void tf_client_free(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
tfContext* tf = (tfContext*) instance->context;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
/* TODO: Client display tear down */
|
||||
}
|
||||
|
||||
static int tf_client_start(rdpContext* context)
|
||||
{
|
||||
/* TODO: Start client related stuff */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tf_client_stop(rdpContext* context)
|
||||
{
|
||||
/* TODO: Stop client related stuff */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
|
||||
pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
|
||||
pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
|
||||
pEntryPoints->GlobalInit = tf_client_global_init;
|
||||
pEntryPoints->GlobalUninit = tf_client_global_uninit;
|
||||
pEntryPoints->ContextSize = sizeof(tfContext);
|
||||
pEntryPoints->ClientNew = tf_client_new;
|
||||
pEntryPoints->ClientFree = tf_client_free;
|
||||
pEntryPoints->ClientStart = tf_client_start;
|
||||
pEntryPoints->ClientStop = tf_client_stop;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
DWORD status;
|
||||
RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
|
||||
rdpContext* context;
|
||||
RdpClientEntry(&clientEntryPoints);
|
||||
context = freerdp_client_context_new(&clientEntryPoints);
|
||||
|
||||
if (!context)
|
||||
goto fail;
|
||||
|
||||
status = freerdp_client_settings_parse_command_line(context->settings, argc,
|
||||
argv, FALSE);
|
||||
status = freerdp_client_settings_command_line_status_print(context->settings,
|
||||
status, argc, argv);
|
||||
|
||||
if (status)
|
||||
return 0;
|
||||
|
||||
if (freerdp_client_start(context) != 0)
|
||||
goto fail;
|
||||
|
||||
rc = tf_client_thread_proc(context->instance);
|
||||
|
||||
if (freerdp_client_stop(context) != 0)
|
||||
rc = -1;
|
||||
|
||||
fail:
|
||||
freerdp_client_context_free(context);
|
||||
return rc;
|
||||
}
|
||||
43
client/Sample/tf_freerdp.h
Normal file
43
client/Sample/tf_freerdp.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Sample Client
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CLIENT_SAMPLE_H
|
||||
#define FREERDP_CLIENT_SAMPLE_H
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/rdpei.h>
|
||||
#include <freerdp/client/tsmf.h>
|
||||
#include <freerdp/client/rail.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
#include <freerdp/client/encomsp.h>
|
||||
|
||||
struct tf_context
|
||||
{
|
||||
rdpContext context;
|
||||
|
||||
/* Channels */
|
||||
RdpeiClientContext* rdpei;
|
||||
RdpgfxClientContext* gfx;
|
||||
EncomspClientContext* encomsp;
|
||||
};
|
||||
typedef struct tf_context tfContext;
|
||||
|
||||
#endif /* FREERDP_CLIENT_SAMPLE_H */
|
||||
@ -25,8 +25,14 @@ include_directories(${CMAKE_SOURCE_DIR}/uwac/include)
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
wlfreerdp.c
|
||||
wlfreerdp.h
|
||||
wlf_disp.c
|
||||
wlf_disp.h
|
||||
wlf_pointer.c
|
||||
wlf_pointer.h
|
||||
wlf_input.c
|
||||
wlf_input.h
|
||||
wlf_cliprdr.c
|
||||
wlf_cliprdr.h
|
||||
wlf_channels.c
|
||||
wlf_channels.h
|
||||
)
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
#include <freerdp/gdi/gfx.h>
|
||||
|
||||
#include "wlf_channels.h"
|
||||
#include "wlf_cliprdr.h"
|
||||
#include "wlf_disp.h"
|
||||
#include "wlfreerdp.h"
|
||||
|
||||
/**
|
||||
@ -62,7 +64,6 @@ void wlf_OnChannelConnectedEventHandler(void* context,
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*) context;
|
||||
rdpSettings* settings;
|
||||
|
||||
settings = wlf->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
@ -74,19 +75,23 @@ void wlf_OnChannelConnectedEventHandler(void* context,
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_init(wlf->context.gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
gdi_graphics_pipeline_init(wlf->context.gdi, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
wlf_cliprdr_init(wlf->clipboard, (CliprdrClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
wlf_encomsp_init(wlf, (EncomspClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
wlf_disp_init(wlf->disp, (DispClientContext*)e->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
void wlf_OnChannelDisconnectedEventHandler(void* context,
|
||||
@ -94,7 +99,6 @@ void wlf_OnChannelDisconnectedEventHandler(void* context,
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*) context;
|
||||
rdpSettings* settings;
|
||||
|
||||
settings = wlf->context.settings;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
@ -106,18 +110,22 @@ void wlf_OnChannelDisconnectedEventHandler(void* context,
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
if (settings->SoftwareGdi)
|
||||
gdi_graphics_pipeline_uninit(wlf->context.gdi,
|
||||
(RdpgfxClientContext*) e->pInterface);
|
||||
gdi_graphics_pipeline_uninit(wlf->context.gdi,
|
||||
(RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
wlf_cliprdr_uninit(wlf->clipboard, (CliprdrClientContext*)e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
wlf_encomsp_uninit(wlf, (EncomspClientContext*) e->pInterface);
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
wlf_disp_uninit(wlf->disp, (DispClientContext*)e->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
895
client/Wayland/wlf_cliprdr.c
Normal file
895
client/Wayland/wlf_cliprdr.c
Normal file
@ -0,0 +1,895 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Wayland Clipboard Redirection
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/image.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/clipboard.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
#include <freerdp/channels/cliprdr.h>
|
||||
|
||||
#include "wlf_cliprdr.h"
|
||||
|
||||
#define MAX_CLIPBOARD_FORMATS 255
|
||||
|
||||
static const char* mime_text[] =
|
||||
{
|
||||
"text/plain",
|
||||
"text/plain;charset=utf-8",
|
||||
"UTF8_STRING",
|
||||
"COMPOUND_TEXT",
|
||||
"TEXT",
|
||||
"STRING"
|
||||
};
|
||||
|
||||
static const char* mime_image[] =
|
||||
{
|
||||
"image/png",
|
||||
"image/bmp",
|
||||
"image/x-bmp",
|
||||
"image/x-MS-bmp",
|
||||
"image/x-icon",
|
||||
"image/x-ico",
|
||||
"image/x-win-bitmap",
|
||||
"image/vmd.microsoft.icon",
|
||||
"application/ico",
|
||||
"image/ico",
|
||||
"image/icon",
|
||||
"image/jpeg",
|
||||
"image/tiff"
|
||||
};
|
||||
|
||||
static const char* mime_html[] =
|
||||
{
|
||||
"text/html"
|
||||
};
|
||||
|
||||
struct wlf_clipboard
|
||||
{
|
||||
wlfContext* wfc;
|
||||
rdpChannels* channels;
|
||||
CliprdrClientContext* context;
|
||||
wLog* log;
|
||||
|
||||
UwacSeat* seat;
|
||||
wClipboard* system;
|
||||
wClipboardDelegate* delegate;
|
||||
|
||||
size_t numClientFormats;
|
||||
CLIPRDR_FORMAT* clientFormats;
|
||||
|
||||
size_t numServerFormats;
|
||||
CLIPRDR_FORMAT* serverFormats;
|
||||
|
||||
BOOL sync;
|
||||
|
||||
/* File clipping */
|
||||
BOOL streams_supported;
|
||||
BOOL file_formats_registered;
|
||||
|
||||
/* Server response stuff */
|
||||
FILE* responseFile;
|
||||
UINT32 responseFormat;
|
||||
const char* responseMime;
|
||||
};
|
||||
|
||||
static BOOL wlf_mime_is_text(const char* mime)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_text); x++)
|
||||
{
|
||||
if (strcmp(mime, mime_text[x]) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL wlf_mime_is_image(const char* mime)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_image); x++)
|
||||
{
|
||||
if (strcmp(mime, mime_image[x]) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL wlf_mime_is_html(const char* mime)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_html); x++)
|
||||
{
|
||||
if (strcmp(mime, mime_html[x]) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void wlf_cliprdr_free_server_formats(wfClipboard* clipboard)
|
||||
{
|
||||
if (clipboard && clipboard->serverFormats)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < clipboard->numServerFormats; j++)
|
||||
{
|
||||
CLIPRDR_FORMAT* format = &clipboard->serverFormats[j];
|
||||
free(format->formatName);
|
||||
}
|
||||
|
||||
free(clipboard->serverFormats);
|
||||
clipboard->serverFormats = NULL;
|
||||
clipboard->numServerFormats = 0;
|
||||
}
|
||||
|
||||
if (clipboard)
|
||||
UwacClipboardOfferDestroy(clipboard->seat);
|
||||
}
|
||||
|
||||
static void wlf_cliprdr_free_client_formats(wfClipboard* clipboard)
|
||||
{
|
||||
if (clipboard && clipboard->numClientFormats)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < clipboard->numClientFormats; j++)
|
||||
{
|
||||
CLIPRDR_FORMAT* format = &clipboard->clientFormats[j];
|
||||
free(format->formatName);
|
||||
}
|
||||
|
||||
free(clipboard->clientFormats);
|
||||
clipboard->clientFormats = NULL;
|
||||
clipboard->numClientFormats = 0;
|
||||
}
|
||||
|
||||
if (clipboard)
|
||||
UwacClipboardOfferDestroy(clipboard->seat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_send_client_format_list(wfClipboard* clipboard)
|
||||
{
|
||||
CLIPRDR_FORMAT_LIST formatList = { 0 };
|
||||
formatList.msgFlags = CB_RESPONSE_OK;
|
||||
formatList.numFormats = (UINT32)clipboard->numClientFormats;
|
||||
formatList.formats = clipboard->clientFormats;
|
||||
return clipboard->context->ClientFormatList(clipboard->context, &formatList);
|
||||
}
|
||||
|
||||
static void wfl_cliprdr_add_client_format_id(wfClipboard* clipboard, UINT32 formatId)
|
||||
{
|
||||
size_t x;
|
||||
CLIPRDR_FORMAT* format;
|
||||
const char* name = ClipboardGetFormatName(clipboard->system, formatId);
|
||||
|
||||
for (x = 0; x < clipboard->numClientFormats; x++)
|
||||
{
|
||||
format = &clipboard->clientFormats[x];
|
||||
|
||||
if (format->formatId == formatId)
|
||||
return;
|
||||
}
|
||||
|
||||
format = realloc(clipboard->clientFormats,
|
||||
(clipboard->numClientFormats + 1) * sizeof(CLIPRDR_FORMAT));
|
||||
|
||||
if (!format)
|
||||
return;
|
||||
|
||||
clipboard->clientFormats = format;
|
||||
format = &clipboard->clientFormats[clipboard->numClientFormats++];
|
||||
format->formatId = formatId;
|
||||
format->formatName = NULL;
|
||||
|
||||
if (name && (formatId >= CF_MAX))
|
||||
format->formatName = _strdup(name);
|
||||
}
|
||||
|
||||
static void wlf_cliprdr_add_client_format(wfClipboard* clipboard, const char* mime)
|
||||
{
|
||||
if (wlf_mime_is_html(mime))
|
||||
{
|
||||
UINT32 formatId = ClipboardGetFormatId(clipboard->system, "HTML Format");
|
||||
wfl_cliprdr_add_client_format_id(clipboard, formatId);
|
||||
}
|
||||
else if (wlf_mime_is_text(mime))
|
||||
{
|
||||
wfl_cliprdr_add_client_format_id(clipboard, CF_TEXT);
|
||||
wfl_cliprdr_add_client_format_id(clipboard, CF_OEMTEXT);
|
||||
wfl_cliprdr_add_client_format_id(clipboard, CF_UNICODETEXT);
|
||||
}
|
||||
else if (wlf_mime_is_image(mime))
|
||||
{
|
||||
UINT32 formatId = ClipboardGetFormatId(clipboard->system, "image/bmp");
|
||||
wfl_cliprdr_add_client_format_id(clipboard, formatId);
|
||||
wfl_cliprdr_add_client_format_id(clipboard, CF_DIB);
|
||||
}
|
||||
|
||||
wlf_cliprdr_send_client_format_list(clipboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_send_data_request(wfClipboard* clipboard,
|
||||
UINT32 formatId)
|
||||
{
|
||||
CLIPRDR_FORMAT_DATA_REQUEST request = { 0 };
|
||||
request.requestedFormatId = formatId;
|
||||
return clipboard->context->ClientFormatDataRequest(clipboard->context,
|
||||
&request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_send_data_response(wfClipboard* clipboard, const BYTE* data,
|
||||
size_t size)
|
||||
{
|
||||
CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
|
||||
if (size > UINT32_MAX)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
|
||||
response.dataLen = (UINT32)size;
|
||||
response.requestedFormatData = data;
|
||||
return clipboard->context->ClientFormatDataResponse(clipboard->context,
|
||||
&response);
|
||||
}
|
||||
|
||||
BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* event)
|
||||
{
|
||||
if (!clipboard || !event)
|
||||
return FALSE;
|
||||
|
||||
if (!clipboard->context)
|
||||
return TRUE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case UWAC_EVENT_CLIPBOARD_AVAILABLE:
|
||||
clipboard->seat = event->seat;
|
||||
return TRUE;
|
||||
|
||||
case UWAC_EVENT_CLIPBOARD_OFFER:
|
||||
WLog_Print(clipboard->log, WLOG_INFO, "client announces mime %s", event->mime);
|
||||
wlf_cliprdr_add_client_format(clipboard, event->mime);
|
||||
return TRUE;
|
||||
|
||||
case UWAC_EVENT_CLIPBOARD_SELECT:
|
||||
WLog_Print(clipboard->log, WLOG_DEBUG, "client announces new data");
|
||||
wlf_cliprdr_free_client_formats(clipboard);
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_send_client_capabilities(wfClipboard* clipboard)
|
||||
{
|
||||
CLIPRDR_CAPABILITIES capabilities;
|
||||
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
|
||||
capabilities.cCapabilitiesSets = 1;
|
||||
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &
|
||||
(generalCapabilitySet);
|
||||
generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
|
||||
generalCapabilitySet.capabilitySetLength = 12;
|
||||
generalCapabilitySet.version = CB_CAPS_VERSION_2;
|
||||
generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES;
|
||||
|
||||
if (clipboard->streams_supported && clipboard->file_formats_registered)
|
||||
generalCapabilitySet.generalFlags |=
|
||||
CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS;
|
||||
|
||||
return clipboard->context->ClientCapabilities(clipboard->context,
|
||||
&capabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_send_client_format_list_response(wfClipboard* clipboard,
|
||||
BOOL status)
|
||||
{
|
||||
CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse;
|
||||
formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE;
|
||||
formatListResponse.msgFlags = status ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
|
||||
formatListResponse.dataLen = 0;
|
||||
return clipboard->context->ClientFormatListResponse(clipboard->context,
|
||||
&formatListResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_monitor_ready(CliprdrClientContext* context,
|
||||
const CLIPRDR_MONITOR_READY* monitorReady)
|
||||
{
|
||||
wfClipboard* clipboard = (wfClipboard*) context->custom;
|
||||
UINT ret;
|
||||
|
||||
WINPR_UNUSED(monitorReady);
|
||||
if ((ret = wlf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK)
|
||||
return ret;
|
||||
|
||||
if ((ret = wlf_cliprdr_send_client_format_list(clipboard)) != CHANNEL_RC_OK)
|
||||
return ret;
|
||||
|
||||
clipboard->sync = TRUE;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_server_capabilities(CliprdrClientContext* context,
|
||||
const CLIPRDR_CAPABILITIES* capabilities)
|
||||
{
|
||||
UINT32 i;
|
||||
const BYTE* capsPtr = (const BYTE*) capabilities->capabilitySets;
|
||||
wfClipboard* clipboard = (wfClipboard*) context->custom;
|
||||
clipboard->streams_supported = FALSE;
|
||||
|
||||
for (i = 0; i < capabilities->cCapabilitiesSets; i++)
|
||||
{
|
||||
const CLIPRDR_CAPABILITY_SET* caps = (const CLIPRDR_CAPABILITY_SET*) capsPtr;
|
||||
|
||||
if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL)
|
||||
{
|
||||
const CLIPRDR_GENERAL_CAPABILITY_SET* generalCaps = (const CLIPRDR_GENERAL_CAPABILITY_SET*) caps;
|
||||
|
||||
if (generalCaps->generalFlags & CB_STREAM_FILECLIP_ENABLED)
|
||||
{
|
||||
clipboard->streams_supported = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
capsPtr += caps->capabilitySetLength;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* mime, int fd)
|
||||
{
|
||||
wfClipboard* clipboard = (wfClipboard*)context;
|
||||
size_t x;
|
||||
WINPR_UNUSED(seat);
|
||||
clipboard->responseMime = NULL;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_html); x++)
|
||||
{
|
||||
const char* mime_cur = mime_html[x];
|
||||
|
||||
if (strcmp(mime_cur, mime) == 0)
|
||||
{
|
||||
clipboard->responseMime = mime_cur;
|
||||
clipboard->responseFormat = ClipboardGetFormatId(clipboard->system, "HTML Format");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_text); x++)
|
||||
{
|
||||
const char* mime_cur = mime_text[x];
|
||||
|
||||
if (strcmp(mime_cur, mime) == 0)
|
||||
{
|
||||
clipboard->responseMime = mime_cur;
|
||||
clipboard->responseFormat = CF_UNICODETEXT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_image); x++)
|
||||
{
|
||||
const char* mime_cur = mime_image[x];
|
||||
|
||||
if (strcmp(mime_cur, mime) == 0)
|
||||
{
|
||||
clipboard->responseMime = mime_cur;
|
||||
clipboard->responseFormat = CF_DIB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (clipboard->responseMime != NULL)
|
||||
{
|
||||
clipboard->responseFile = fdopen(fd, "w");
|
||||
|
||||
if (clipboard->responseFile)
|
||||
wlf_cliprdr_send_data_request(clipboard, clipboard->responseFormat);
|
||||
else
|
||||
WLog_Print(clipboard->log, WLOG_ERROR, "failed to open clipboard file descriptor for MIME %s",
|
||||
clipboard->responseMime);
|
||||
}
|
||||
}
|
||||
|
||||
static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context)
|
||||
{
|
||||
WINPR_UNUSED(seat);
|
||||
WINPR_UNUSED(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the clipboard changes server side.
|
||||
*
|
||||
* Clear the local clipboard offer and replace it with a new one
|
||||
* that announces the formats we get listed here.
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
const CLIPRDR_FORMAT_LIST* formatList)
|
||||
{
|
||||
UINT32 i;
|
||||
wfClipboard* clipboard;
|
||||
BOOL html = FALSE;
|
||||
BOOL text = FALSE;
|
||||
BOOL image = FALSE;
|
||||
|
||||
if (!context || !context->custom)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
clipboard = (wfClipboard*) context->custom;
|
||||
wlf_cliprdr_free_server_formats(clipboard);
|
||||
|
||||
if (!(clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc(
|
||||
formatList->numFormats, sizeof(CLIPRDR_FORMAT))))
|
||||
{
|
||||
WLog_Print(clipboard->log, WLOG_ERROR, "failed to allocate %"PRIuz" CLIPRDR_FORMAT structs",
|
||||
clipboard->numServerFormats);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
clipboard->numServerFormats = formatList->numFormats;
|
||||
|
||||
if (!clipboard->seat)
|
||||
{
|
||||
WLog_Print(clipboard->log, WLOG_ERROR, "clipboard->seat=NULL, check your client implementation");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < formatList->numFormats; i++)
|
||||
{
|
||||
const CLIPRDR_FORMAT* format = &formatList->formats[i];
|
||||
CLIPRDR_FORMAT* srvFormat = &clipboard->serverFormats[i];
|
||||
srvFormat->formatId = format->formatId;
|
||||
|
||||
if (format->formatName)
|
||||
{
|
||||
srvFormat->formatName = _strdup(format->formatName);
|
||||
|
||||
if (!srvFormat->formatName)
|
||||
{
|
||||
wlf_cliprdr_free_server_formats(clipboard);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if (format->formatName)
|
||||
{
|
||||
if (strcmp(format->formatName, "HTML Format") == 0)
|
||||
{
|
||||
text = TRUE;
|
||||
html = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (format->formatId)
|
||||
{
|
||||
case CF_TEXT:
|
||||
case CF_OEMTEXT:
|
||||
case CF_UNICODETEXT:
|
||||
text = TRUE;
|
||||
break;
|
||||
|
||||
case CF_DIB:
|
||||
image = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (html)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_html); x++)
|
||||
UwacClipboardOfferCreate(clipboard->seat, mime_html[x]);
|
||||
}
|
||||
|
||||
if (text)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_text); x++)
|
||||
UwacClipboardOfferCreate(clipboard->seat, mime_text[x]);
|
||||
}
|
||||
|
||||
if (image)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(mime_image); x++)
|
||||
UwacClipboardOfferCreate(clipboard->seat, mime_image[x]);
|
||||
}
|
||||
|
||||
UwacClipboardOfferAnnounce(clipboard->seat, clipboard, wlf_cliprdr_transfer_data,
|
||||
wlf_cliprdr_cancel_data);
|
||||
return wlf_cliprdr_send_client_format_list_response(clipboard, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_server_format_list_response(CliprdrClientContext*
|
||||
context, const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
|
||||
{
|
||||
//wfClipboard* clipboard = (wfClipboard*) context->custom;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_server_format_data_request(CliprdrClientContext* context,
|
||||
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
|
||||
{
|
||||
int cnv;
|
||||
UINT rc;
|
||||
BYTE* data;
|
||||
LPWSTR cdata;
|
||||
size_t size;
|
||||
const char* mime;
|
||||
UINT32 formatId = formatDataRequest->requestedFormatId;
|
||||
wfClipboard* clipboard = (wfClipboard*) context->custom;
|
||||
|
||||
switch (formatId)
|
||||
{
|
||||
case CF_TEXT:
|
||||
case CF_OEMTEXT:
|
||||
case CF_UNICODETEXT:
|
||||
mime = "text/plain;charset=utf-8";
|
||||
break;
|
||||
|
||||
case CF_DIB:
|
||||
case CF_DIBV5:
|
||||
mime = "image/bmp";
|
||||
break;
|
||||
|
||||
default:
|
||||
if (formatId == ClipboardGetFormatId(clipboard->system, "HTML Format"))
|
||||
mime = "text/html";
|
||||
else if (formatId == ClipboardGetFormatId(clipboard->system, "image/bmp"))
|
||||
mime = "image/bmp";
|
||||
else
|
||||
mime = ClipboardGetFormatName(clipboard->system, formatId);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
data = UwacClipboardDataGet(clipboard->seat, mime, &size);
|
||||
|
||||
if (!data)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
switch (formatId)
|
||||
{
|
||||
case CF_UNICODETEXT:
|
||||
if (size > INT_MAX)
|
||||
rc = ERROR_INTERNAL_ERROR;
|
||||
else
|
||||
{
|
||||
cnv = ConvertToUnicode(CP_UTF8, 0, (LPCSTR)data, (int)size, &cdata, 0);
|
||||
free(data);
|
||||
data = NULL;
|
||||
|
||||
if (cnv < 0)
|
||||
rc = ERROR_INTERNAL_ERROR;
|
||||
else
|
||||
{
|
||||
size = (size_t)cnv;
|
||||
data = (BYTE*)cdata;
|
||||
size *= sizeof(WCHAR);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// TODO: Image conversions
|
||||
break;
|
||||
}
|
||||
|
||||
rc = wlf_cliprdr_send_data_response(clipboard, data, size);
|
||||
free(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT wlf_cliprdr_server_format_data_response(CliprdrClientContext*
|
||||
context, const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
|
||||
{
|
||||
int cnv;
|
||||
UINT rc = ERROR_INTERNAL_ERROR;
|
||||
UINT32 size = formatDataResponse->dataLen;
|
||||
LPSTR cdata = NULL;
|
||||
LPCSTR data = (LPCSTR)formatDataResponse->requestedFormatData;
|
||||
const WCHAR* wdata = (const WCHAR*)formatDataResponse->requestedFormatData;
|
||||
wfClipboard* clipboard = (wfClipboard*) context->custom;
|
||||
|
||||
if (size > INT_MAX * sizeof(WCHAR))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
switch (clipboard->responseFormat)
|
||||
{
|
||||
case CF_UNICODETEXT:
|
||||
cnv = ConvertFromUnicode(CP_UTF8, 0, wdata, (int)(size / sizeof(WCHAR)), &cdata, 0, NULL, NULL);
|
||||
if (cnv < 0)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
size = (size_t)cnv;
|
||||
data = cdata;
|
||||
break;
|
||||
|
||||
default:
|
||||
// TODO: Image conversions
|
||||
break;
|
||||
}
|
||||
|
||||
fwrite(data, 1, size, clipboard->responseFile);
|
||||
fclose(clipboard->responseFile);
|
||||
rc = CHANNEL_RC_OK;
|
||||
free(cdata);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_server_file_size_request(wfClipboard* clipboard,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wClipboardFileSizeRequest request = { 0 };
|
||||
request.streamId = fileContentsRequest->streamId;
|
||||
request.listIndex = fileContentsRequest->listIndex;
|
||||
|
||||
if (fileContentsRequest->cbRequested != sizeof(UINT64))
|
||||
{
|
||||
WLog_Print(clipboard->log, WLOG_WARN, "unexpected FILECONTENTS_SIZE request: %"PRIu32" bytes",
|
||||
fileContentsRequest->cbRequested);
|
||||
}
|
||||
|
||||
return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request);
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_server_file_range_request(wfClipboard* clipboard,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wClipboardFileRangeRequest request = { 0 };
|
||||
request.streamId = fileContentsRequest->streamId;
|
||||
request.listIndex = fileContentsRequest->listIndex;
|
||||
request.nPositionLow = fileContentsRequest->nPositionLow;
|
||||
request.nPositionHigh = fileContentsRequest->nPositionHigh;
|
||||
request.cbRequested = fileContentsRequest->cbRequested;
|
||||
return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request);
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_send_file_contents_failure(CliprdrClientContext* context,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = fileContentsRequest->streamId;
|
||||
response.dwFlags = fileContentsRequest->dwFlags;
|
||||
return context->ClientFileContentsResponse(context, &response);
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
UINT error = NO_ERROR;
|
||||
wfClipboard* clipboard = context->custom;
|
||||
|
||||
/*
|
||||
* MS-RDPECLIP 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST):
|
||||
* The FILECONTENTS_SIZE and FILECONTENTS_RANGE flags MUST NOT be set at the same time.
|
||||
*/
|
||||
if ((fileContentsRequest->dwFlags & (FILECONTENTS_SIZE | FILECONTENTS_RANGE)) ==
|
||||
(FILECONTENTS_SIZE | FILECONTENTS_RANGE))
|
||||
{
|
||||
WLog_Print(clipboard->log, WLOG_ERROR, "invalid CLIPRDR_FILECONTENTS_REQUEST.dwFlags");
|
||||
return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest);
|
||||
}
|
||||
|
||||
if (fileContentsRequest->dwFlags & FILECONTENTS_SIZE)
|
||||
error = wlf_cliprdr_server_file_size_request(clipboard, fileContentsRequest);
|
||||
|
||||
if (fileContentsRequest->dwFlags & FILECONTENTS_RANGE)
|
||||
error = wlf_cliprdr_server_file_range_request(clipboard, fileContentsRequest);
|
||||
|
||||
if (error)
|
||||
{
|
||||
WLog_Print(clipboard->log, WLOG_ERROR, "failed to handle CLIPRDR_FILECONTENTS_REQUEST: 0x%08X",
|
||||
error);
|
||||
return wlf_cliprdr_send_file_contents_failure(context, fileContentsRequest);
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate,
|
||||
const wClipboardFileSizeRequest* request, UINT64 fileSize)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
wfClipboard* clipboard = delegate->custom;
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_SIZE;
|
||||
response.cbRequested = sizeof(UINT64);
|
||||
response.requestedData = (BYTE*) &fileSize;
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate,
|
||||
const wClipboardFileSizeRequest* request, UINT errorCode)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
wfClipboard* clipboard = delegate->custom;
|
||||
|
||||
WINPR_UNUSED(errorCode);
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_SIZE;
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate,
|
||||
const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
wfClipboard* clipboard = delegate->custom;
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_RANGE;
|
||||
response.cbRequested = size;
|
||||
response.requestedData = (const BYTE*) data;
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate,
|
||||
const wClipboardFileRangeRequest* request, UINT errorCode)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
wfClipboard* clipboard = delegate->custom;
|
||||
|
||||
WINPR_UNUSED(errorCode);
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_RANGE;
|
||||
return clipboard->context->ClientFileContentsResponse(clipboard->context, &response);
|
||||
}
|
||||
|
||||
wfClipboard* wlf_clipboard_new(wlfContext* wfc)
|
||||
{
|
||||
rdpChannels* channels;
|
||||
wfClipboard* clipboard;
|
||||
|
||||
if (!(clipboard = (wfClipboard*) calloc(1, sizeof(wfClipboard))))
|
||||
return NULL;
|
||||
|
||||
clipboard->wfc = wfc;
|
||||
channels = wfc->context.channels;
|
||||
clipboard->log = WLog_Get(TAG);
|
||||
clipboard->channels = channels;
|
||||
clipboard->system = ClipboardCreate();
|
||||
clipboard->delegate = ClipboardGetDelegate(clipboard->system);
|
||||
clipboard->delegate->custom = clipboard;
|
||||
clipboard->delegate->ClipboardFileSizeSuccess = wlf_cliprdr_clipboard_file_size_success;
|
||||
clipboard->delegate->ClipboardFileSizeFailure = wlf_cliprdr_clipboard_file_size_failure;
|
||||
clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success;
|
||||
clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure;
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
void wlf_clipboard_free(wfClipboard* clipboard)
|
||||
{
|
||||
if (!clipboard)
|
||||
return;
|
||||
|
||||
wlf_cliprdr_free_server_formats(clipboard);
|
||||
wlf_cliprdr_free_client_formats(clipboard);
|
||||
ClipboardDestroy(clipboard->system);
|
||||
free(clipboard);
|
||||
}
|
||||
|
||||
BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr)
|
||||
{
|
||||
if (!cliprdr || !clipboard)
|
||||
return FALSE;
|
||||
|
||||
clipboard->context = cliprdr;
|
||||
cliprdr->custom = (void*) clipboard;
|
||||
cliprdr->MonitorReady = wlf_cliprdr_monitor_ready;
|
||||
cliprdr->ServerCapabilities = wlf_cliprdr_server_capabilities;
|
||||
cliprdr->ServerFormatList = wlf_cliprdr_server_format_list;
|
||||
cliprdr->ServerFormatListResponse = wlf_cliprdr_server_format_list_response;
|
||||
cliprdr->ServerFormatDataRequest = wlf_cliprdr_server_format_data_request;
|
||||
cliprdr->ServerFormatDataResponse = wlf_cliprdr_server_format_data_response;
|
||||
cliprdr->ServerFileContentsRequest = wlf_cliprdr_server_file_contents_request;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wlf_cliprdr_uninit(wfClipboard* clipboard, CliprdrClientContext* cliprdr)
|
||||
{
|
||||
if (cliprdr)
|
||||
cliprdr->custom = NULL;
|
||||
|
||||
if (clipboard)
|
||||
clipboard->context = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
36
client/Wayland/wlf_cliprdr.h
Normal file
36
client/Wayland/wlf_cliprdr.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Wayland Clipboard Redirection
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CLIENT_WAYLAND_CLIPRDR_H
|
||||
#define FREERDP_CLIENT_WAYLAND_CLIPRDR_H
|
||||
|
||||
#include "wlfreerdp.h"
|
||||
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
wfClipboard* wlf_clipboard_new(wlfContext* wlc);
|
||||
void wlf_clipboard_free(wfClipboard* clipboard);
|
||||
|
||||
BOOL wlf_cliprdr_init(wfClipboard* clipboard, CliprdrClientContext* cliprdr);
|
||||
BOOL wlf_cliprdr_uninit(wfClipboard* clipboard, CliprdrClientContext* cliprdr);
|
||||
|
||||
BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* event);
|
||||
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_CLIPRDR_H */
|
||||
374
client/Wayland/wlf_disp.c
Normal file
374
client/Wayland/wlf_disp.c
Normal file
@ -0,0 +1,374 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Wayland Display Control Channel
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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/sysinfo.h>
|
||||
|
||||
#include "wlf_disp.h"
|
||||
|
||||
#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
|
||||
|
||||
struct _wlfDispContext
|
||||
{
|
||||
wlfContext* wlc;
|
||||
DispClientContext* disp;
|
||||
BOOL haveXRandr;
|
||||
int eventBase, errorBase;
|
||||
int lastSentWidth, lastSentHeight;
|
||||
UINT64 lastSentDate;
|
||||
int targetWidth, targetHeight;
|
||||
BOOL activated;
|
||||
BOOL waitingResize;
|
||||
BOOL fullscreen;
|
||||
UINT16 lastSentDesktopOrientation;
|
||||
UINT32 lastSentDesktopScaleFactor;
|
||||
UINT32 lastSentDeviceScaleFactor;
|
||||
};
|
||||
|
||||
static UINT wlf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, size_t nmonitors);
|
||||
|
||||
static BOOL wlf_disp_settings_changed(wlfDispContext* wlfDisp)
|
||||
{
|
||||
rdpSettings* settings = wlfDisp->wlc->context.settings;
|
||||
|
||||
if (wlfDisp->lastSentWidth != wlfDisp->targetWidth)
|
||||
return TRUE;
|
||||
|
||||
if (wlfDisp->lastSentHeight != wlfDisp->targetHeight)
|
||||
return TRUE;
|
||||
|
||||
if (wlfDisp->lastSentDesktopOrientation != settings->DesktopOrientation)
|
||||
return TRUE;
|
||||
|
||||
if (wlfDisp->lastSentDesktopScaleFactor != settings->DesktopScaleFactor)
|
||||
return TRUE;
|
||||
|
||||
if (wlfDisp->lastSentDeviceScaleFactor != settings->DeviceScaleFactor)
|
||||
return TRUE;
|
||||
|
||||
if (wlfDisp->fullscreen != wlfDisp->wlc->fullscreen)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL wlf_update_last_sent(wlfDispContext* wlfDisp)
|
||||
{
|
||||
rdpSettings* settings = wlfDisp->wlc->context.settings;
|
||||
wlfDisp->lastSentWidth = wlfDisp->targetWidth;
|
||||
wlfDisp->lastSentHeight = wlfDisp->targetHeight;
|
||||
wlfDisp->lastSentDesktopOrientation = settings->DesktopOrientation;
|
||||
wlfDisp->lastSentDesktopScaleFactor = settings->DesktopScaleFactor;
|
||||
wlfDisp->lastSentDeviceScaleFactor = settings->DeviceScaleFactor;
|
||||
wlfDisp->fullscreen = wlfDisp->wlc->fullscreen;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wlf_disp_sendResize(wlfDispContext* wlfDisp)
|
||||
{
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT layout;
|
||||
wlfContext* wlc;
|
||||
rdpSettings* settings;
|
||||
|
||||
if (!wlfDisp || !wlfDisp->wlc)
|
||||
return FALSE;
|
||||
|
||||
wlc = wlfDisp->wlc;
|
||||
settings = wlc->context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
if (!wlfDisp->activated || !wlfDisp->disp)
|
||||
return TRUE;
|
||||
|
||||
if (GetTickCount64() - wlfDisp->lastSentDate < RESIZE_MIN_DELAY)
|
||||
return TRUE;
|
||||
|
||||
wlfDisp->lastSentDate = GetTickCount64();
|
||||
|
||||
if (!wlf_disp_settings_changed(wlfDisp))
|
||||
return TRUE;
|
||||
|
||||
/* TODO: Multimonitor support for wayland
|
||||
if (wlc->fullscreen && (settings->MonitorCount > 0))
|
||||
{
|
||||
if (wlf_disp_sendLayout(wlfDisp->disp, settings->MonitorDefArray,
|
||||
settings->MonitorCount) != CHANNEL_RC_OK)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
wlfDisp->waitingResize = TRUE;
|
||||
layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
|
||||
layout.Top = layout.Left = 0;
|
||||
layout.Width = wlfDisp->targetWidth;
|
||||
layout.Height = wlfDisp->targetHeight;
|
||||
layout.Orientation = settings->DesktopOrientation;
|
||||
layout.DesktopScaleFactor = settings->DesktopScaleFactor;
|
||||
layout.DeviceScaleFactor = settings->DeviceScaleFactor;
|
||||
layout.PhysicalWidth = wlfDisp->targetWidth;
|
||||
layout.PhysicalHeight = wlfDisp->targetHeight;
|
||||
|
||||
if (IFCALLRESULT(CHANNEL_RC_OK, wlfDisp->disp->SendMonitorLayout, wlfDisp->disp, 1,
|
||||
&layout) != CHANNEL_RC_OK)
|
||||
return FALSE;
|
||||
}
|
||||
return wlf_update_last_sent(wlfDisp);
|
||||
}
|
||||
|
||||
static BOOL wlf_disp_set_window_resizable(wlfDispContext* wlfDisp)
|
||||
{
|
||||
#if 0 // TODO
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wlf_disp_check_context(void* context, wlfContext** ppwlc, wlfDispContext** ppwlfDisp,
|
||||
rdpSettings** ppSettings)
|
||||
{
|
||||
wlfContext* wlc;
|
||||
|
||||
if (!context)
|
||||
return FALSE;
|
||||
|
||||
wlc = (wlfContext*)context;
|
||||
|
||||
if (!(wlc->disp))
|
||||
return FALSE;
|
||||
|
||||
if (!wlc->context.settings)
|
||||
return FALSE;
|
||||
|
||||
*ppwlc = wlc;
|
||||
*ppwlfDisp = wlc->disp;
|
||||
*ppSettings = wlc->context.settings;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void wlf_disp_OnActivated(void* context, ActivatedEventArgs* e)
|
||||
{
|
||||
wlfContext* wlc;
|
||||
wlfDispContext* wlfDisp;
|
||||
rdpSettings* settings;
|
||||
|
||||
if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
|
||||
return;
|
||||
|
||||
wlfDisp->waitingResize = FALSE;
|
||||
|
||||
if (wlfDisp->activated && !settings->Fullscreen)
|
||||
{
|
||||
wlf_disp_set_window_resizable(wlfDisp);
|
||||
|
||||
if (e->firstActivation)
|
||||
return;
|
||||
|
||||
wlf_disp_sendResize(wlfDisp);
|
||||
}
|
||||
}
|
||||
|
||||
static void wlf_disp_OnGraphicsReset(void* context, GraphicsResetEventArgs* e)
|
||||
{
|
||||
wlfContext* wlc;
|
||||
wlfDispContext* wlfDisp;
|
||||
rdpSettings* settings;
|
||||
|
||||
if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
|
||||
return;
|
||||
|
||||
wlfDisp->waitingResize = FALSE;
|
||||
|
||||
if (wlfDisp->activated && !settings->Fullscreen)
|
||||
{
|
||||
wlf_disp_set_window_resizable(wlfDisp);
|
||||
wlf_disp_sendResize(wlfDisp);
|
||||
}
|
||||
}
|
||||
|
||||
static void wlf_disp_OnTimer(void* context, TimerEventArgs* e)
|
||||
{
|
||||
wlfContext* wlc;
|
||||
wlfDispContext* wlfDisp;
|
||||
rdpSettings* settings;
|
||||
|
||||
if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
|
||||
return;
|
||||
|
||||
if (!wlfDisp->activated || settings->Fullscreen)
|
||||
return;
|
||||
|
||||
wlf_disp_sendResize(wlfDisp);
|
||||
}
|
||||
|
||||
wlfDispContext* wlf_disp_new(wlfContext* wlc)
|
||||
{
|
||||
wlfDispContext* ret;
|
||||
|
||||
if (!wlc || !wlc->context.settings || !wlc->context.pubSub)
|
||||
return NULL;
|
||||
|
||||
ret = calloc(1, sizeof(wlfDispContext));
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
ret->wlc = wlc;
|
||||
ret->lastSentWidth = ret->targetWidth = wlc->context.settings->DesktopWidth;
|
||||
ret->lastSentHeight = ret->targetHeight = wlc->context.settings->DesktopHeight;
|
||||
PubSub_SubscribeActivated(wlc->context.pubSub, wlf_disp_OnActivated);
|
||||
PubSub_SubscribeGraphicsReset(wlc->context.pubSub, wlf_disp_OnGraphicsReset);
|
||||
PubSub_SubscribeTimer(wlc->context.pubSub, wlf_disp_OnTimer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wlf_disp_free(wlfDispContext* disp)
|
||||
{
|
||||
if (!disp)
|
||||
return;
|
||||
|
||||
if (disp->wlc)
|
||||
{
|
||||
PubSub_UnsubscribeActivated(disp->wlc->context.pubSub, wlf_disp_OnActivated);
|
||||
PubSub_UnsubscribeGraphicsReset(disp->wlc->context.pubSub, wlf_disp_OnGraphicsReset);
|
||||
PubSub_UnsubscribeTimer(disp->wlc->context.pubSub, wlf_disp_OnTimer);
|
||||
}
|
||||
|
||||
free(disp);
|
||||
}
|
||||
|
||||
UINT wlf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, size_t nmonitors)
|
||||
{
|
||||
UINT ret = CHANNEL_RC_OK;
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT* layouts;
|
||||
size_t i;
|
||||
wlfDispContext* wlfDisp = (wlfDispContext*)disp->custom;
|
||||
rdpSettings* settings = wlfDisp->wlc->context.settings;
|
||||
layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
|
||||
|
||||
if (!layouts)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
for (i = 0; i < nmonitors; i++)
|
||||
{
|
||||
layouts[i].Flags = (monitors[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
|
||||
layouts[i].Left = monitors[i].x;
|
||||
layouts[i].Top = monitors[i].y;
|
||||
layouts[i].Width = monitors[i].width;
|
||||
layouts[i].Height = monitors[i].height;
|
||||
layouts[i].Orientation = ORIENTATION_LANDSCAPE;
|
||||
layouts[i].PhysicalWidth = monitors[i].attributes.physicalWidth;
|
||||
layouts[i].PhysicalHeight = monitors[i].attributes.physicalHeight;
|
||||
|
||||
switch (monitors[i].attributes.orientation)
|
||||
{
|
||||
case 90:
|
||||
layouts[i].Orientation = ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
|
||||
case 180:
|
||||
layouts[i].Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
|
||||
case 270:
|
||||
layouts[i].Orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
/* MS-RDPEDISP - 2.2.2.2.1:
|
||||
* Orientation (4 bytes): A 32-bit unsigned integer that specifies the
|
||||
* orientation of the monitor in degrees. Valid values are 0, 90, 180
|
||||
* or 270
|
||||
*
|
||||
* So we default to ORIENTATION_LANDSCAPE
|
||||
*/
|
||||
layouts[i].Orientation = ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
}
|
||||
|
||||
layouts[i].DesktopScaleFactor = settings->DesktopScaleFactor;
|
||||
layouts[i].DeviceScaleFactor = settings->DeviceScaleFactor;
|
||||
}
|
||||
|
||||
ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts);
|
||||
free(layouts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height)
|
||||
{
|
||||
if (!disp)
|
||||
return FALSE;
|
||||
|
||||
disp->targetWidth = width;
|
||||
disp->targetHeight = height;
|
||||
return wlf_disp_sendResize(disp);
|
||||
}
|
||||
|
||||
static UINT wlf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
|
||||
UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
|
||||
{
|
||||
/* we're called only if dynamic resolution update is activated */
|
||||
wlfDispContext* wlfDisp = (wlfDispContext*)disp->custom;
|
||||
rdpSettings* settings = wlfDisp->wlc->context.settings;
|
||||
WLog_DBG(TAG,
|
||||
"DisplayControlCapsPdu: MaxNumMonitors: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"",
|
||||
maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
|
||||
wlfDisp->activated = TRUE;
|
||||
|
||||
if (settings->Fullscreen)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
|
||||
return wlf_disp_set_window_resizable(wlfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
BOOL wlf_disp_init(wlfDispContext* wlfDisp, DispClientContext* disp)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
|
||||
if (!wlfDisp || !wlfDisp->wlc || !disp)
|
||||
return FALSE;
|
||||
|
||||
settings = wlfDisp->wlc->context.settings;
|
||||
|
||||
if (!settings)
|
||||
return FALSE;
|
||||
|
||||
wlfDisp->disp = disp;
|
||||
disp->custom = (void*) wlfDisp;
|
||||
|
||||
if (settings->DynamicResolutionUpdate)
|
||||
{
|
||||
disp->DisplayControlCaps = wlf_DisplayControlCaps;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wlf_disp_uninit(wlfDispContext* wlfDisp, DispClientContext* disp)
|
||||
{
|
||||
if (!wlfDisp || !disp)
|
||||
return FALSE;
|
||||
|
||||
wlfDisp->disp = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
36
client/Wayland/wlf_disp.h
Normal file
36
client/Wayland/wlf_disp.h
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Wayland Display Control Channel
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 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.
|
||||
*/
|
||||
#ifndef FREERDP_CLIENT_WAYLAND_DISP_H
|
||||
#define FREERDP_CLIENT_WAYLAND_DISP_H
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
|
||||
#include "wlfreerdp.h"
|
||||
|
||||
FREERDP_API BOOL wlf_disp_init(wlfDispContext* xfDisp, DispClientContext* disp);
|
||||
FREERDP_API BOOL wlf_disp_uninit(wlfDispContext* xfDisp, DispClientContext* disp);
|
||||
|
||||
wlfDispContext* wlf_disp_new(wlfContext* wlc);
|
||||
void wlf_disp_free(wlfDispContext* disp);
|
||||
BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height);
|
||||
void wlf_disp_resized(wlfDispContext* disp);
|
||||
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_DISP_H */
|
||||
@ -44,7 +44,8 @@ BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev)
|
||||
BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev)
|
||||
{
|
||||
rdpInput* input;
|
||||
UINT16 flags;
|
||||
UINT16 flags = 0;
|
||||
UINT16 xflags = 0;
|
||||
|
||||
if (!instance || !ev || !instance->input)
|
||||
return FALSE;
|
||||
@ -52,9 +53,10 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev)
|
||||
input = instance->input;
|
||||
|
||||
if (ev->state == WL_POINTER_BUTTON_STATE_PRESSED)
|
||||
flags = PTR_FLAGS_DOWN;
|
||||
else
|
||||
flags = 0;
|
||||
{
|
||||
flags |= PTR_FLAGS_DOWN;
|
||||
xflags |= PTR_XFLAGS_DOWN;
|
||||
}
|
||||
|
||||
switch (ev->button)
|
||||
{
|
||||
@ -70,36 +72,59 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev)
|
||||
flags |= PTR_FLAGS_BUTTON3;
|
||||
break;
|
||||
|
||||
case BTN_SIDE:
|
||||
xflags |= PTR_XFLAGS_BUTTON1;
|
||||
break;
|
||||
|
||||
case BTN_EXTRA:
|
||||
xflags |= PTR_XFLAGS_BUTTON2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y);
|
||||
if ((flags & ~PTR_FLAGS_DOWN) != 0)
|
||||
return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y);
|
||||
|
||||
if ((xflags & ~PTR_XFLAGS_DOWN) != 0)
|
||||
return freerdp_input_send_extended_mouse_event(input, xflags, ev->x, ev->y);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev)
|
||||
{
|
||||
rdpInput* input;
|
||||
UINT16 flags;
|
||||
UINT16 flags = 0;
|
||||
int direction;
|
||||
|
||||
if (!instance || !ev || !instance->input)
|
||||
return FALSE;
|
||||
|
||||
input = instance->input;
|
||||
flags = PTR_FLAGS_WHEEL;
|
||||
|
||||
if (ev->axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||
switch (ev->axis)
|
||||
{
|
||||
direction = wl_fixed_to_int(ev->value);
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
flags |= PTR_FLAGS_WHEEL;
|
||||
break;
|
||||
|
||||
if (direction < 0)
|
||||
flags |= 0x0078;
|
||||
else
|
||||
flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088;
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
flags |= PTR_FLAGS_HWHEEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
direction = wl_fixed_to_int(ev->value);
|
||||
flags |= 0x0078; /* TODO: Calculate the distance with the provided value size */
|
||||
|
||||
if (direction < 0)
|
||||
flags |= PTR_FLAGS_WHEEL_NEGATIVE;
|
||||
|
||||
return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y);
|
||||
}
|
||||
|
||||
@ -129,5 +154,5 @@ BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev)
|
||||
|
||||
input = instance->input;
|
||||
return freerdp_input_send_focus_in_event(input, 0) &&
|
||||
freerdp_input_send_mouse_event(input, PTR_FLAGS_MOVE, 0, 0);
|
||||
freerdp_input_send_mouse_event(input, PTR_FLAGS_MOVE, 0, 0);
|
||||
}
|
||||
|
||||
133
client/Wayland/wlf_pointer.c
Normal file
133
client/Wayland/wlf_pointer.c
Normal file
@ -0,0 +1,133 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Wayland Mouse Pointer
|
||||
*
|
||||
* Copyright 2019 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "wlf_pointer.h"
|
||||
#include "wlfreerdp.h"
|
||||
|
||||
struct wlf_pointer
|
||||
{
|
||||
rdpPointer pointer;
|
||||
size_t size;
|
||||
void* data;
|
||||
};
|
||||
typedef struct wlf_pointer wlfPointer;
|
||||
|
||||
static BOOL wlf_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
wlfPointer* ptr = (wlfPointer*)pointer;
|
||||
if (!ptr)
|
||||
return FALSE;
|
||||
|
||||
ptr->size = pointer->width * pointer->height * 4;
|
||||
ptr->data = _aligned_malloc(ptr->size, 16);
|
||||
if (!ptr->data)
|
||||
return FALSE;
|
||||
|
||||
if (!freerdp_image_copy_from_pointer_data(
|
||||
ptr->data, PIXEL_FORMAT_RGBA32,
|
||||
0, 0, 0, pointer->width, pointer->height,
|
||||
pointer->xorMaskData, pointer->lengthXorMask,
|
||||
pointer->andMaskData, pointer->lengthAndMask,
|
||||
pointer->xorBpp, &context->gdi->palette))
|
||||
{
|
||||
_aligned_free(ptr->data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void wlf_Pointer_Free(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
wlfPointer* ptr = (wlfPointer*)pointer;
|
||||
WINPR_UNUSED(context);
|
||||
if (ptr)
|
||||
_aligned_free(ptr->data);
|
||||
}
|
||||
|
||||
static BOOL wlf_Pointer_Set(rdpContext* context,
|
||||
const rdpPointer* pointer)
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*)context;
|
||||
wlfPointer* ptr = (wlfPointer*)pointer;
|
||||
|
||||
if (!wlf || !wlf->seat)
|
||||
return FALSE;
|
||||
|
||||
// TODO: Scale according to SmartSizing
|
||||
if (UwacSeatSetMouseCursor(wlf->seat, ptr->data, ptr->size, pointer->width, pointer->height, pointer->xPos, pointer->yPos) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wlf_Pointer_SetNull(rdpContext* context)
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*)context;
|
||||
if (!wlf || !wlf->seat)
|
||||
return FALSE;
|
||||
|
||||
if (UwacSeatSetMouseCursor(wlf->seat, NULL, 0, 0, 0, 0, 0) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wlf_Pointer_SetDefault(rdpContext* context)
|
||||
{
|
||||
wlfContext* wlf = (wlfContext*)context;
|
||||
if (!wlf || !wlf->seat)
|
||||
return FALSE;
|
||||
|
||||
if (UwacSeatSetMouseCursor(wlf->seat, NULL, 1, 0, 0, 0, 0) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wlf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
|
||||
{
|
||||
// TODO
|
||||
WLog_WARN(TAG, "%s not implemented", __FUNCTION__);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL wlf_register_pointer(rdpGraphics* graphics)
|
||||
{
|
||||
rdpPointer* pointer = NULL;
|
||||
|
||||
if (!(pointer = (rdpPointer*) calloc(1, sizeof(rdpPointer))))
|
||||
return FALSE;
|
||||
|
||||
pointer->size = sizeof(wlfPointer);
|
||||
pointer->New = wlf_Pointer_New;
|
||||
pointer->Free = wlf_Pointer_Free;
|
||||
pointer->Set = wlf_Pointer_Set;
|
||||
pointer->SetNull = wlf_Pointer_SetNull;
|
||||
pointer->SetDefault = wlf_Pointer_SetDefault;
|
||||
pointer->SetPosition = wlf_Pointer_SetPosition;
|
||||
graphics_register_pointer(graphics, pointer);
|
||||
free(pointer);
|
||||
return TRUE;
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* DirectFB Event Handling
|
||||
* Wayland Mouse Pointer
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2019 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2019 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.
|
||||
@ -17,12 +18,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CLIENT_DF_EVENT_H
|
||||
#define FREERDP_CLIENT_DF_EVENT_H
|
||||
#ifndef FREERDP_CLIENT_WAYLAND_POINTER_H
|
||||
#define FREERDP_CLIENT_WAYLAND_POINTER_H
|
||||
|
||||
#include "dfreerdp.h"
|
||||
#include <freerdp/graphics.h>
|
||||
|
||||
void df_keyboard_init(void);
|
||||
BOOL df_event_process(freerdp* instance, DFBEvent* event);
|
||||
BOOL wlf_register_pointer(rdpGraphics* graphics);
|
||||
|
||||
#endif /* FREERDP_CLIENT_DF_EVENT_H */
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_POINTER_H */
|
||||
@ -36,22 +36,10 @@
|
||||
|
||||
#include "wlfreerdp.h"
|
||||
#include "wlf_input.h"
|
||||
#include "wlf_cliprdr.h"
|
||||
#include "wlf_disp.h"
|
||||
#include "wlf_channels.h"
|
||||
|
||||
static BOOL wl_update_content(wlfContext* context_w)
|
||||
{
|
||||
if (!context_w)
|
||||
return FALSE;
|
||||
|
||||
if (!context_w->waitingFrameDone && context_w->haveDamage)
|
||||
{
|
||||
UwacWindowSubmitBuffer(context_w->window, true);
|
||||
context_w->waitingFrameDone = TRUE;
|
||||
context_w->haveDamage = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#include "wlf_pointer.h"
|
||||
|
||||
static BOOL wl_begin_paint(rdpContext* context)
|
||||
{
|
||||
@ -69,15 +57,68 @@ static BOOL wl_begin_paint(rdpContext* context)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw, INT32 ih)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
char* data;
|
||||
size_t baseSrcOffset;
|
||||
size_t baseDstOffset;
|
||||
UINT32 i, x, y, w, h;
|
||||
UwacSize geometry;
|
||||
size_t stride;
|
||||
UwacReturnCode rc;
|
||||
|
||||
if (!context_w)
|
||||
return FALSE;
|
||||
|
||||
if ((ix < 0) || (iy < 0) || (iw < 0) || (ih < 0))
|
||||
return FALSE;
|
||||
|
||||
x = (UINT32)ix;
|
||||
y = (UINT32)iy;
|
||||
w = (UINT32)iw;
|
||||
h = (UINT32)ih;
|
||||
rc = UwacWindowGetDrawingBufferGeometry(context_w->window, &geometry, &stride);
|
||||
data = UwacWindowGetDrawingBuffer(context_w->window);
|
||||
|
||||
if (!data || (rc != UWAC_SUCCESS))
|
||||
return FALSE;
|
||||
|
||||
gdi = context_w->context.gdi;
|
||||
|
||||
if (!gdi)
|
||||
return FALSE;
|
||||
|
||||
/* Ignore output if the surface size does not match. */
|
||||
if ((x > geometry.width) || (y > geometry.height))
|
||||
return TRUE;
|
||||
|
||||
baseSrcOffset = y * gdi->stride + x * GetBytesPerPixel(gdi->dstFormat);
|
||||
baseDstOffset = y * stride + x * 4;
|
||||
for (i = 0; i < MIN(h, geometry.height - y); i++)
|
||||
{
|
||||
const size_t srcOffset = i * gdi->stride + baseSrcOffset;
|
||||
const size_t dstOffset = i * stride + baseDstOffset;
|
||||
|
||||
memcpy(data + dstOffset, gdi->primary_buffer + srcOffset,
|
||||
MIN(w, geometry.width - x) * GetBytesPerPixel(gdi->dstFormat));
|
||||
}
|
||||
|
||||
if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
if (UwacWindowSubmitBuffer(context_w->window, true) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL wl_end_paint(rdpContext* context)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
char* data;
|
||||
wlfContext* context_w;
|
||||
INT32 x, y;
|
||||
UINT32 w, h;
|
||||
UINT32 i;
|
||||
INT32 w, h;
|
||||
|
||||
if (!context || !context->gdi || !context->gdi->primary)
|
||||
return FALSE;
|
||||
@ -92,27 +133,31 @@ static BOOL wl_end_paint(rdpContext* context)
|
||||
w = gdi->primary->hdc->hwnd->invalid->w;
|
||||
h = gdi->primary->hdc->hwnd->invalid->h;
|
||||
context_w = (wlfContext*) context;
|
||||
data = UwacWindowGetDrawingBuffer(context_w->window);
|
||||
|
||||
if (!data)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
memcpy(data + ((i + y) * (gdi->width * GetBytesPerPixel(
|
||||
gdi->dstFormat))) + x * GetBytesPerPixel(gdi->dstFormat),
|
||||
gdi->primary_buffer + ((i + y) * (gdi->width * GetBytesPerPixel(
|
||||
gdi->dstFormat))) + x * GetBytesPerPixel(gdi->dstFormat),
|
||||
w * GetBytesPerPixel(gdi->dstFormat));
|
||||
}
|
||||
|
||||
if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
context_w->haveDamage = TRUE;
|
||||
return wl_update_content(context_w);
|
||||
return wl_update_buffer(context_w, x, y, w, h);
|
||||
}
|
||||
|
||||
static BOOL wl_refresh_display(wlfContext* context)
|
||||
{
|
||||
rdpGdi* gdi;
|
||||
|
||||
if (!context || !context->context.gdi)
|
||||
return FALSE;
|
||||
|
||||
gdi = context->context.gdi;
|
||||
return wl_update_buffer(context, 0, 0, gdi->width, gdi->height);
|
||||
}
|
||||
|
||||
static BOOL wl_resize_display(rdpContext* context)
|
||||
{
|
||||
wlfContext* wlc = (wlfContext*)context;
|
||||
rdpGdi* gdi = context->gdi;
|
||||
rdpSettings* settings = context->settings;
|
||||
|
||||
if (!gdi_resize(gdi, settings->DesktopWidth, settings->DesktopHeight))
|
||||
return FALSE;
|
||||
|
||||
return wl_refresh_display(wlc);
|
||||
}
|
||||
|
||||
static BOOL wl_pre_connect(freerdp* instance)
|
||||
{
|
||||
@ -132,31 +177,6 @@ static BOOL wl_pre_connect(freerdp* instance)
|
||||
|
||||
settings->OsMajorType = OSMAJORTYPE_UNIX;
|
||||
settings->OsMinorType = OSMINORTYPE_NATIVE_WAYLAND;
|
||||
ZeroMemory(settings->OrderSupport, 32);
|
||||
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_MEM3BLT_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
||||
PubSub_SubscribeChannelConnected(instance->context->pubSub,
|
||||
wlf_OnChannelConnectedEventHandler);
|
||||
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
|
||||
@ -190,6 +210,7 @@ static BOOL wl_post_connect(freerdp* instance)
|
||||
rdpGdi* gdi;
|
||||
UwacWindow* window;
|
||||
wlfContext* context;
|
||||
UINT32 w, h;
|
||||
|
||||
if (!instance || !instance->context)
|
||||
return FALSE;
|
||||
@ -199,27 +220,37 @@ static BOOL wl_post_connect(freerdp* instance)
|
||||
|
||||
gdi = instance->context->gdi;
|
||||
|
||||
if (!gdi)
|
||||
if (!gdi || (gdi->width < 0) || (gdi->height < 0))
|
||||
return FALSE;
|
||||
|
||||
if (!wlf_register_pointer(instance->context->graphics))
|
||||
return FALSE;
|
||||
|
||||
w = (UINT32)gdi->width;
|
||||
h = (UINT32)gdi->height;
|
||||
context = (wlfContext*) instance->context;
|
||||
context->window = window = UwacCreateWindowShm(context->display, gdi->width,
|
||||
gdi->height, WL_SHM_FORMAT_XRGB8888);
|
||||
context->window = window = UwacCreateWindowShm(context->display, w, h, WL_SHM_FORMAT_XRGB8888);
|
||||
|
||||
if (!window)
|
||||
return FALSE;
|
||||
|
||||
UwacWindowSetFullscreenState(window, NULL, instance->context->settings->Fullscreen);
|
||||
UwacWindowSetTitle(window, "FreeRDP");
|
||||
UwacWindowSetOpaqueRegion(context->window, 0, 0, gdi->width, gdi->height);
|
||||
UwacWindowSetOpaqueRegion(context->window, 0, 0, w, h);
|
||||
instance->update->BeginPaint = wl_begin_paint;
|
||||
instance->update->EndPaint = wl_end_paint;
|
||||
memcpy(UwacWindowGetDrawingBuffer(context->window), gdi->primary_buffer,
|
||||
gdi->width * gdi->height * 4);
|
||||
UwacWindowAddDamage(context->window, 0, 0, gdi->width, gdi->height);
|
||||
context->haveDamage = TRUE;
|
||||
instance->update->DesktopResize = wl_resize_display;
|
||||
freerdp_keyboard_init(instance->context->settings->KeyboardLayout);
|
||||
return wl_update_content(context);
|
||||
|
||||
if (!(context->disp = wlf_disp_new(context)))
|
||||
return FALSE;
|
||||
|
||||
context->clipboard = wlf_clipboard_new(context);
|
||||
|
||||
if (!context->clipboard)
|
||||
return FALSE;
|
||||
|
||||
return wl_refresh_display(context);
|
||||
}
|
||||
|
||||
static void wl_post_disconnect(freerdp* instance)
|
||||
@ -234,6 +265,8 @@ static void wl_post_disconnect(freerdp* instance)
|
||||
|
||||
context = (wlfContext*) instance->context;
|
||||
gdi_free(instance);
|
||||
wlf_clipboard_free(context->clipboard);
|
||||
wlf_disp_free(context->disp);
|
||||
|
||||
if (context->window)
|
||||
UwacDestroyWindow(&context->window);
|
||||
@ -247,6 +280,8 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
|
||||
if (UwacDisplayDispatch(display, 1) < 0)
|
||||
return FALSE;
|
||||
|
||||
context = (wlfContext*)instance->context;
|
||||
|
||||
while (UwacHasEvent(display))
|
||||
{
|
||||
if (UwacNextEvent(display, &event) != UWAC_SUCCESS)
|
||||
@ -255,16 +290,15 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
|
||||
/*printf("UWAC event type %d\n", event.type);*/
|
||||
switch (event.type)
|
||||
{
|
||||
case UWAC_EVENT_NEW_SEAT:
|
||||
context->seat = event.seat_new.seat;
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_REMOVED_SEAT:
|
||||
context->seat = NULL;
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_FRAME_DONE:
|
||||
if (!instance)
|
||||
continue;
|
||||
|
||||
context = (wlfContext*)instance->context;
|
||||
context->waitingFrameDone = FALSE;
|
||||
|
||||
if (context->haveDamage && !wl_update_content(context))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_POINTER_ENTER:
|
||||
@ -298,11 +332,30 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_KEYBOARD_ENTER:
|
||||
if (instance->context->settings->GrabKeyboard)
|
||||
UwacSeatInhibitShortcuts(event.keyboard_enter_leave.seat, true);
|
||||
if (!wlf_keyboard_enter(instance, &event.keyboard_enter_leave))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_CONFIGURE:
|
||||
if (!wlf_disp_handle_configure(context->disp, event.configure.width, event.configure.height))
|
||||
return FALSE;
|
||||
|
||||
if (!wl_refresh_display(context))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
case UWAC_EVENT_CLIPBOARD_AVAILABLE:
|
||||
case UWAC_EVENT_CLIPBOARD_OFFER:
|
||||
case UWAC_EVENT_CLIPBOARD_SELECT:
|
||||
if (!wlf_cliprdr_handle_event(context->clipboard, &event.clipboard))
|
||||
return FALSE;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -328,7 +381,7 @@ static int wlfreerdp_run(freerdp* instance)
|
||||
|
||||
if (!freerdp_connect(instance))
|
||||
{
|
||||
printf("Failed to connect\n");
|
||||
WLog_Print(context->log, WLOG_ERROR, "Failed to connect");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -339,7 +392,7 @@ static int wlfreerdp_run(freerdp* instance)
|
||||
|
||||
if (count <= 1)
|
||||
{
|
||||
printf("Failed to get FreeRDP file descriptor\n");
|
||||
WLog_Print(context->log, WLOG_ERROR, "Failed to get FreeRDP file descriptor");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -347,20 +400,20 @@ static int wlfreerdp_run(freerdp* instance)
|
||||
|
||||
if (WAIT_FAILED == status)
|
||||
{
|
||||
printf("%s: WaitForMultipleObjects failed\n", __FUNCTION__);
|
||||
WLog_Print(context->log, WLOG_ERROR, "%s: WaitForMultipleObjects failed", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handle_uwac_events(instance, context->display))
|
||||
{
|
||||
printf("error handling UWAC events\n");
|
||||
WLog_Print(context->log, WLOG_ERROR, "error handling UWAC events");
|
||||
break;
|
||||
}
|
||||
|
||||
if (freerdp_check_event_handles(instance->context) != TRUE)
|
||||
{
|
||||
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
|
||||
printf("Failed to check FreeRDP file descriptor\n");
|
||||
WLog_Print(context->log, WLOG_ERROR, "Failed to check FreeRDP file descriptor");
|
||||
|
||||
break;
|
||||
}
|
||||
@ -394,7 +447,7 @@ static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
|
||||
return -1;
|
||||
|
||||
wlf = (wlfContext*) instance->context;
|
||||
WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
|
||||
WLog_Print(wlf->log, WLOG_INFO, "Logon Error Info %s [%s]", str_data, str_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -411,12 +464,13 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context)
|
||||
instance->PostDisconnect = wl_post_disconnect;
|
||||
instance->Authenticate = client_cli_authenticate;
|
||||
instance->GatewayAuthenticate = client_cli_gw_authenticate;
|
||||
instance->VerifyCertificate = client_cli_verify_certificate;
|
||||
instance->VerifyChangedCertificate = client_cli_verify_changed_certificate;
|
||||
instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
|
||||
instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
|
||||
instance->LogonErrorInfo = wlf_logon_error_info;
|
||||
wfl->log = WLog_Get(TAG);
|
||||
wfl->display = UwacOpenDisplay(NULL, &status);
|
||||
|
||||
if (!wfl->display || (status != UWAC_SUCCESS))
|
||||
if (!wfl->display || (status != UWAC_SUCCESS) || !wfl->log)
|
||||
return FALSE;
|
||||
|
||||
wfl->displayHandle = CreateFileDescriptorEvent(NULL, FALSE, FALSE,
|
||||
@ -445,11 +499,13 @@ static void wlf_client_free(freerdp* instance, rdpContext* context)
|
||||
|
||||
static int wfl_client_start(rdpContext* context)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wfl_client_stop(rdpContext* context)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -471,7 +527,7 @@ static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
DWORD status;
|
||||
int status;
|
||||
RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
|
||||
rdpContext* context;
|
||||
RdpClientEntry(&clientEntryPoints);
|
||||
|
||||
@ -31,7 +31,8 @@
|
||||
#define TAG CLIENT_TAG("wayland")
|
||||
|
||||
typedef struct wlf_context wlfContext;
|
||||
|
||||
typedef struct wlf_clipboard wfClipboard;
|
||||
typedef struct _wlfDispContext wlfDispContext;
|
||||
|
||||
struct wlf_context
|
||||
{
|
||||
@ -40,14 +41,17 @@ struct wlf_context
|
||||
UwacDisplay* display;
|
||||
HANDLE displayHandle;
|
||||
UwacWindow* window;
|
||||
UwacSeat* seat;
|
||||
|
||||
BOOL waitingFrameDone;
|
||||
BOOL haveDamage;
|
||||
BOOL fullscreen;
|
||||
|
||||
/* Channels */
|
||||
RdpeiClientContext* rdpei;
|
||||
RdpgfxClientContext* gfx;
|
||||
EncomspClientContext* encomsp;
|
||||
wfClipboard* clipboard;
|
||||
wlfDispContext* disp;
|
||||
wLog* log;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CLIENT_WAYLAND_FREERDP_H */
|
||||
|
||||
@ -501,6 +501,37 @@ static BOOL xf_process_x_events(freerdp* instance)
|
||||
return status;
|
||||
}
|
||||
|
||||
static char* xf_window_get_title(rdpSettings* settings)
|
||||
{
|
||||
BOOL port;
|
||||
char* windowTitle;
|
||||
size_t size;
|
||||
char* name;
|
||||
const char* prefix = "FreeRDP:";
|
||||
|
||||
if (!settings)
|
||||
return NULL;
|
||||
|
||||
name = settings->ServerHostname;
|
||||
|
||||
if (settings->WindowTitle)
|
||||
return _strdup(settings->WindowTitle);
|
||||
|
||||
port = (settings->ServerPort != 3389);
|
||||
size = strlen(name) + 16;
|
||||
windowTitle = calloc(size, sizeof(char));
|
||||
|
||||
if (!windowTitle)
|
||||
return NULL;
|
||||
|
||||
if (!port)
|
||||
sprintf_s(windowTitle, size, "%s %s", prefix, name);
|
||||
else
|
||||
sprintf_s(windowTitle, size, "%s %s:%i", prefix, name, settings->ServerPort);
|
||||
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
BOOL xf_create_window(xfContext* xfc)
|
||||
{
|
||||
XGCValues gcv;
|
||||
@ -532,37 +563,10 @@ BOOL xf_create_window(xfContext* xfc)
|
||||
xfc->offset_x = 0;
|
||||
xfc->offset_y = 0;
|
||||
#endif
|
||||
windowTitle = xf_window_get_title(settings);
|
||||
|
||||
if (settings->WindowTitle)
|
||||
{
|
||||
windowTitle = _strdup(settings->WindowTitle);
|
||||
|
||||
if (!windowTitle)
|
||||
return FALSE;
|
||||
}
|
||||
else if (settings->ServerPort == 3389)
|
||||
{
|
||||
size_t size = 1 + sizeof("FreeRDP: ") + strlen(
|
||||
settings->ServerHostname);
|
||||
windowTitle = malloc(size);
|
||||
|
||||
if (!windowTitle)
|
||||
return FALSE;
|
||||
|
||||
sprintf_s(windowTitle, size, "FreeRDP: %s", settings->ServerHostname);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size = 1 + sizeof("FreeRDP: ") + strlen(settings->ServerHostname)
|
||||
+ sizeof(":00000");
|
||||
windowTitle = malloc(size);
|
||||
|
||||
if (!windowTitle)
|
||||
return FALSE;
|
||||
|
||||
sprintf_s(windowTitle, size, "FreeRDP: %s:%i", settings->ServerHostname,
|
||||
settings->ServerPort);
|
||||
}
|
||||
if (!windowTitle)
|
||||
return FALSE;
|
||||
|
||||
#ifdef WITH_XRENDER
|
||||
|
||||
@ -1032,26 +1036,55 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map)
|
||||
|
||||
/* Assignment of physical (not logical) mouse buttons to wire flags. */
|
||||
/* Notice that the middle button is 2 in X11, but 3 in RDP. */
|
||||
static const int xf_button_flags[NUM_BUTTONS_MAPPED] =
|
||||
static const button_map xf_button_flags[NUM_BUTTONS_MAPPED] =
|
||||
{
|
||||
PTR_FLAGS_BUTTON1,
|
||||
PTR_FLAGS_BUTTON3,
|
||||
PTR_FLAGS_BUTTON2
|
||||
{Button1, PTR_FLAGS_BUTTON1},
|
||||
{Button2, PTR_FLAGS_BUTTON3},
|
||||
{Button3, PTR_FLAGS_BUTTON2},
|
||||
{Button4, PTR_FLAGS_WHEEL | 0x78},
|
||||
{Button5, PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x78},
|
||||
{6, PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x78},
|
||||
{7, PTR_FLAGS_HWHEEL | 0x78},
|
||||
{8, PTR_XFLAGS_BUTTON1},
|
||||
{9, PTR_XFLAGS_BUTTON2},
|
||||
{97, PTR_XFLAGS_BUTTON1},
|
||||
{112, PTR_XFLAGS_BUTTON2}
|
||||
};
|
||||
|
||||
static UINT16 get_flags_for_button(int button)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x = 0; x < ARRAYSIZE(xf_button_flags); x++)
|
||||
{
|
||||
const button_map* map = &xf_button_flags[x];
|
||||
|
||||
if (map->button == button)
|
||||
return map->flags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xf_button_map_init(xfContext* xfc)
|
||||
{
|
||||
size_t pos = 0;
|
||||
/* loop counter for array initialization */
|
||||
int physical;
|
||||
int logical;
|
||||
size_t physical;
|
||||
/* logical mouse button which is used for each physical mouse */
|
||||
/* button (indexed from zero). This is the default map. */
|
||||
unsigned char x11_map[NUM_BUTTONS_MAPPED] =
|
||||
{
|
||||
Button1,
|
||||
Button2,
|
||||
Button3
|
||||
};
|
||||
unsigned char x11_map[112] = { 0 };
|
||||
x11_map[0] = Button1;
|
||||
x11_map[1] = Button2;
|
||||
x11_map[2] = Button3;
|
||||
x11_map[3] = Button4;
|
||||
x11_map[4] = Button5;
|
||||
x11_map[5] = 6;
|
||||
x11_map[6] = 7;
|
||||
x11_map[7] = 8;
|
||||
x11_map[8] = 9;
|
||||
x11_map[96] = 97;
|
||||
x11_map[111] = 112;
|
||||
|
||||
/* query system for actual remapping */
|
||||
if (!xfc->context.settings->UnmapButtons)
|
||||
@ -1062,18 +1095,23 @@ static void xf_button_map_init(xfContext* xfc)
|
||||
/* iterate over all (mapped) physical buttons; for each of them */
|
||||
/* find the logical button in X11, and assign to this the */
|
||||
/* appropriate value to send over the RDP wire. */
|
||||
for (physical = 0; physical < NUM_BUTTONS_MAPPED; ++physical)
|
||||
for (physical = 0; physical < ARRAYSIZE(x11_map); ++physical)
|
||||
{
|
||||
logical = x11_map[physical];
|
||||
const unsigned char logical = x11_map[physical];
|
||||
const UINT16 flags = get_flags_for_button(logical);
|
||||
|
||||
if (Button1 <= logical && logical <= Button3)
|
||||
if ((logical != 0) && (flags != 0))
|
||||
{
|
||||
xfc->button_map[logical - BUTTON_BASE] = xf_button_flags[physical];
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "Mouse physical button %d is mapped to logical button %d",
|
||||
physical, logical);
|
||||
if (pos >= NUM_BUTTONS_MAPPED)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to map mouse button to RDP button, no space");
|
||||
}
|
||||
else
|
||||
{
|
||||
button_map* map = &xfc->button_map[pos++];
|
||||
map->button = physical + Button1;
|
||||
map->flags = get_flags_for_button(logical);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1100,31 +1138,6 @@ static BOOL xf_pre_connect(freerdp* instance)
|
||||
channels = context->channels;
|
||||
settings->OsMajorType = OSMAJORTYPE_UNIX;
|
||||
settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER;
|
||||
ZeroMemory(settings->OrderSupport, 32);
|
||||
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_LINETO_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
|
||||
settings->OrderSupport[NEG_MEMBLT_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_MEM3BLT_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = settings->BitmapCacheEnabled;
|
||||
settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE;
|
||||
settings->OrderSupport[NEG_FAST_INDEX_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE;
|
||||
settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = settings->GlyphSupportLevel != GLYPH_SUPPORT_NONE;
|
||||
settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
|
||||
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
|
||||
PubSub_SubscribeChannelConnected(instance->context->pubSub,
|
||||
xf_OnChannelConnectedEventHandler);
|
||||
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
|
||||
@ -1189,7 +1202,6 @@ static BOOL xf_pre_connect(freerdp* instance)
|
||||
xfc->decorations = settings->Decorations;
|
||||
xfc->grab_keyboard = settings->GrabKeyboard;
|
||||
xfc->fullscreen_toggle = settings->ToggleFullscreen;
|
||||
xfc->floatbar = settings->Floatbar;
|
||||
xf_button_map_init(xfc);
|
||||
return TRUE;
|
||||
}
|
||||
@ -1571,8 +1583,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param)
|
||||
nCount += tmp;
|
||||
}
|
||||
|
||||
if (xfc->floatbar && xfc->fullscreen && !xfc->remote_app)
|
||||
xf_floatbar_hide_and_show(xfc);
|
||||
if (xfc->window)
|
||||
xf_floatbar_hide_and_show(xfc->window->floatbar);
|
||||
|
||||
waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
|
||||
|
||||
@ -1788,8 +1800,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
instance->PostDisconnect = xf_post_disconnect;
|
||||
instance->Authenticate = client_cli_authenticate;
|
||||
instance->GatewayAuthenticate = client_cli_gw_authenticate;
|
||||
instance->VerifyCertificate = client_cli_verify_certificate;
|
||||
instance->VerifyChangedCertificate = client_cli_verify_changed_certificate;
|
||||
instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
|
||||
instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
|
||||
instance->LogonErrorInfo = xf_logon_error_info;
|
||||
PubSub_SubscribeTerminate(context->pubSub,
|
||||
xf_TerminateEventHandler);
|
||||
@ -1884,7 +1896,7 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context)
|
||||
xfc->_NET_WM_WINDOW_TYPE_POPUP = XInternAtom(xfc->display,
|
||||
"_NET_WM_WINDOW_TYPE_POPUP", False);
|
||||
xfc->_NET_WM_WINDOW_TYPE_POPUP_MENU = XInternAtom(xfc->display,
|
||||
"_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
|
||||
"_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
|
||||
xfc->_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(xfc->display,
|
||||
"_NET_WM_WINDOW_TYPE_UTILITY", False);
|
||||
xfc->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(xfc->display,
|
||||
|
||||
@ -266,8 +266,7 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom(
|
||||
static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard,
|
||||
UINT32 formatId)
|
||||
{
|
||||
CLIPRDR_FORMAT_DATA_REQUEST request;
|
||||
ZeroMemory(&request, sizeof(CLIPRDR_FORMAT_DATA_REQUEST));
|
||||
CLIPRDR_FORMAT_DATA_REQUEST request = { 0 };
|
||||
request.requestedFormatId = formatId;
|
||||
return clipboard->context->ClientFormatDataRequest(clipboard->context,
|
||||
&request);
|
||||
@ -281,8 +280,7 @@ static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard,
|
||||
static UINT xf_cliprdr_send_data_response(xfClipboard* clipboard, BYTE* data,
|
||||
int size)
|
||||
{
|
||||
CLIPRDR_FORMAT_DATA_RESPONSE response;
|
||||
ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE));
|
||||
CLIPRDR_FORMAT_DATA_RESPONSE response = { 0 };
|
||||
response.msgFlags = (data) ? CB_RESPONSE_OK : CB_RESPONSE_FAIL;
|
||||
response.dataLen = size;
|
||||
response.requestedFormatData = data;
|
||||
@ -545,9 +543,8 @@ static void xf_cliprdr_get_requested_targets(xfClipboard* clipboard)
|
||||
{
|
||||
UINT32 numFormats = 0;
|
||||
CLIPRDR_FORMAT* formats = NULL;
|
||||
CLIPRDR_FORMAT_LIST formatList;
|
||||
CLIPRDR_FORMAT_LIST formatList = { 0 };
|
||||
formats = xf_cliprdr_get_client_formats(clipboard, &numFormats);
|
||||
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
|
||||
formatList.msgFlags = CB_RESPONSE_OK;
|
||||
formatList.numFormats = numFormats;
|
||||
formatList.formats = formats;
|
||||
@ -1096,10 +1093,9 @@ static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard)
|
||||
{
|
||||
UINT32 i, numFormats;
|
||||
CLIPRDR_FORMAT* formats = NULL;
|
||||
CLIPRDR_FORMAT_LIST formatList;
|
||||
CLIPRDR_FORMAT_LIST formatList = { 0 };
|
||||
xfContext* xfc = clipboard->xfc;
|
||||
UINT ret;
|
||||
ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST));
|
||||
numFormats = clipboard->numClientFormats;
|
||||
|
||||
if (numFormats)
|
||||
@ -1155,7 +1151,7 @@ static UINT xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_cliprdr_monitor_ready(CliprdrClientContext* context,
|
||||
CLIPRDR_MONITOR_READY* monitorReady)
|
||||
const CLIPRDR_MONITOR_READY* monitorReady)
|
||||
{
|
||||
xfClipboard* clipboard = (xfClipboard*) context->custom;
|
||||
UINT ret;
|
||||
@ -1176,7 +1172,7 @@ static UINT xf_cliprdr_monitor_ready(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context,
|
||||
CLIPRDR_CAPABILITIES* capabilities)
|
||||
const CLIPRDR_CAPABILITIES* capabilities)
|
||||
{
|
||||
UINT32 i;
|
||||
const CLIPRDR_CAPABILITY_SET* caps;
|
||||
@ -1211,7 +1207,7 @@ static UINT xf_cliprdr_server_capabilities(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_LIST* formatList)
|
||||
const CLIPRDR_FORMAT_LIST* formatList)
|
||||
{
|
||||
UINT32 i;
|
||||
int j;
|
||||
@ -1301,7 +1297,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_cliprdr_server_format_list_response(CliprdrClientContext*
|
||||
context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
|
||||
context, const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
|
||||
{
|
||||
//xfClipboard* clipboard = (xfClipboard*) context->custom;
|
||||
return CHANNEL_RC_OK;
|
||||
@ -1313,7 +1309,7 @@ static UINT xf_cliprdr_server_format_list_response(CliprdrClientContext*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context,
|
||||
CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
|
||||
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
|
||||
{
|
||||
BOOL rawTransfer;
|
||||
xfCliprdrFormat* format = NULL;
|
||||
@ -1348,7 +1344,7 @@ static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context,
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext*
|
||||
context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
|
||||
context, const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
BYTE* pDstData;
|
||||
@ -1477,8 +1473,7 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext*
|
||||
static UINT xf_cliprdr_server_file_size_request(xfClipboard* clipboard,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wClipboardFileSizeRequest request;
|
||||
ZeroMemory(&request, sizeof(request));
|
||||
wClipboardFileSizeRequest request = { 0 };
|
||||
request.streamId = fileContentsRequest->streamId;
|
||||
request.listIndex = fileContentsRequest->listIndex;
|
||||
|
||||
@ -1494,8 +1489,7 @@ static UINT xf_cliprdr_server_file_size_request(xfClipboard* clipboard,
|
||||
static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
wClipboardFileRangeRequest request;
|
||||
ZeroMemory(&request, sizeof(request));
|
||||
wClipboardFileRangeRequest request = { 0 };
|
||||
request.streamId = fileContentsRequest->streamId;
|
||||
request.listIndex = fileContentsRequest->listIndex;
|
||||
request.nPositionLow = fileContentsRequest->nPositionLow;
|
||||
@ -1507,8 +1501,7 @@ static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard,
|
||||
static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context,
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = fileContentsRequest->streamId;
|
||||
response.dwFlags = fileContentsRequest->dwFlags;
|
||||
@ -1516,7 +1509,7 @@ static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context,
|
||||
}
|
||||
|
||||
static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* context,
|
||||
CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
|
||||
{
|
||||
UINT error = NO_ERROR;
|
||||
xfClipboard* clipboard = context->custom;
|
||||
@ -1550,9 +1543,8 @@ static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* contex
|
||||
static UINT xf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate,
|
||||
const wClipboardFileSizeRequest* request, UINT64 fileSize)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_SIZE;
|
||||
@ -1564,9 +1556,8 @@ static UINT xf_cliprdr_clipboard_file_size_success(wClipboardDelegate* delegate,
|
||||
static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate,
|
||||
const wClipboardFileSizeRequest* request, UINT errorCode)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_SIZE;
|
||||
@ -1576,9 +1567,8 @@ static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate,
|
||||
static UINT xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate,
|
||||
const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
response.msgFlags = CB_RESPONSE_OK;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_RANGE;
|
||||
@ -1590,9 +1580,8 @@ static UINT xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate
|
||||
static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate,
|
||||
const wClipboardFileRangeRequest* request, UINT errorCode)
|
||||
{
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response;
|
||||
CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
|
||||
xfClipboard* clipboard = delegate->custom;
|
||||
ZeroMemory(&response, sizeof(response));
|
||||
response.msgFlags = CB_RESPONSE_FAIL;
|
||||
response.streamId = request->streamId;
|
||||
response.dwFlags = FILECONTENTS_RANGE;
|
||||
|
||||
@ -409,7 +409,7 @@ static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors
|
||||
if (settings->Fullscreen)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizeable");
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
|
||||
return xf_disp_set_window_resizable(xfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
@ -213,7 +213,7 @@ static BOOL xf_event_execute_action_script(xfContext* xfc, XEvent* event)
|
||||
char buffer[1024] = { 0 };
|
||||
char command[1024] = { 0 };
|
||||
|
||||
if (!xfc->actionScriptExists || !xfc->xevents)
|
||||
if (!xfc->actionScriptExists || !xfc->xevents || !xfc->window)
|
||||
return FALSE;
|
||||
|
||||
if (event->type > LASTEvent)
|
||||
@ -367,79 +367,58 @@ static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app)
|
||||
if (xfc->use_xinput)
|
||||
return TRUE;
|
||||
|
||||
if(xfc->floatbar && !(app))
|
||||
xf_floatbar_set_root_y(xfc, event->xmotion.y);
|
||||
if (xfc->window)
|
||||
xf_floatbar_set_root_y(xfc->window->floatbar, event->xmotion.y);
|
||||
|
||||
return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y,
|
||||
event->xmotion.state, event->xmotion.window, app);
|
||||
}
|
||||
BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button,
|
||||
Window window, BOOL app)
|
||||
|
||||
BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button,
|
||||
Window window, BOOL app, BOOL down)
|
||||
{
|
||||
int flags;
|
||||
BOOL wheel;
|
||||
BOOL extended;
|
||||
UINT16 flags = 0;
|
||||
rdpInput* input;
|
||||
Window childWindow;
|
||||
wheel = FALSE;
|
||||
extended = FALSE;
|
||||
input = xfc->context.input;
|
||||
size_t i;
|
||||
|
||||
switch (button)
|
||||
for (i = 0; i < ARRAYSIZE(xfc->button_map); i++)
|
||||
{
|
||||
case Button1:
|
||||
case Button2:
|
||||
case Button3:
|
||||
flags = PTR_FLAGS_DOWN | xfc->button_map[button - BUTTON_BASE];
|
||||
break;
|
||||
const button_map* cur = &xfc->button_map[i];
|
||||
|
||||
case 4:
|
||||
wheel = TRUE;
|
||||
flags = PTR_FLAGS_WHEEL | 0x0078;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
wheel = TRUE;
|
||||
flags = PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0078;
|
||||
break;
|
||||
|
||||
case 8: /* back */
|
||||
case 97: /* Xming */
|
||||
extended = TRUE;
|
||||
flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON1;
|
||||
break;
|
||||
|
||||
case 9: /* forward */
|
||||
case 112: /* Xming */
|
||||
extended = TRUE;
|
||||
flags = PTR_XFLAGS_DOWN | PTR_XFLAGS_BUTTON2;
|
||||
break;
|
||||
|
||||
case 6: /* wheel left */
|
||||
wheel = TRUE;
|
||||
flags = PTR_FLAGS_HWHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x0078;
|
||||
break;
|
||||
|
||||
case 7: /* wheel right */
|
||||
wheel = TRUE;
|
||||
flags = PTR_FLAGS_HWHEEL | 0x0078;
|
||||
break;
|
||||
|
||||
default:
|
||||
x = 0;
|
||||
y = 0;
|
||||
flags = 0;
|
||||
if (cur->button == button)
|
||||
{
|
||||
flags = cur->flags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
input = xfc->context.input;
|
||||
|
||||
if (flags != 0)
|
||||
{
|
||||
if (wheel)
|
||||
if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))
|
||||
{
|
||||
freerdp_input_send_mouse_event(input, flags, 0, 0);
|
||||
if (down)
|
||||
freerdp_input_send_mouse_event(input, flags, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL extended = FALSE;
|
||||
|
||||
if (flags & (PTR_XFLAGS_BUTTON1 | PTR_XFLAGS_BUTTON2))
|
||||
{
|
||||
extended = TRUE;
|
||||
|
||||
if (down)
|
||||
flags |= PTR_XFLAGS_DOWN;
|
||||
}
|
||||
else if (flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3))
|
||||
{
|
||||
if (down)
|
||||
flags |= PTR_FLAGS_DOWN;
|
||||
}
|
||||
|
||||
if (app)
|
||||
{
|
||||
/* make sure window exists */
|
||||
@ -468,80 +447,17 @@ static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app)
|
||||
if (xfc->use_xinput)
|
||||
return TRUE;
|
||||
|
||||
return xf_generic_ButtonPress(xfc, event->xbutton.x, event->xbutton.y,
|
||||
event->xbutton.button, event->xbutton.window, app);
|
||||
return xf_generic_ButtonEvent(xfc, event->xbutton.x, event->xbutton.y,
|
||||
event->xbutton.button, event->xbutton.window, app, TRUE);
|
||||
}
|
||||
BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button,
|
||||
Window window, BOOL app)
|
||||
{
|
||||
int flags = 0;
|
||||
BOOL extended = FALSE;
|
||||
rdpInput* input;
|
||||
Window childWindow;
|
||||
|
||||
if (!xfc || !xfc->context.input)
|
||||
return FALSE;
|
||||
|
||||
input = xfc->context.input;
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case Button1:
|
||||
case Button2:
|
||||
case Button3:
|
||||
flags = xfc->button_map[button - BUTTON_BASE];
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case 8:
|
||||
case 97:
|
||||
extended = TRUE;
|
||||
flags = PTR_XFLAGS_BUTTON1;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
case 9:
|
||||
case 112:
|
||||
extended = TRUE;
|
||||
flags = PTR_XFLAGS_BUTTON2;
|
||||
break;
|
||||
|
||||
default:
|
||||
flags = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags != 0)
|
||||
{
|
||||
if (app)
|
||||
{
|
||||
/* make sure window exists */
|
||||
if (!xf_AppWindowFromX11Window(xfc, window))
|
||||
return TRUE;
|
||||
|
||||
/* Translate to desktop coordinates */
|
||||
XTranslateCoordinates(xfc->display, window,
|
||||
RootWindowOfScreen(xfc->screen),
|
||||
x, y, &x, &y, &childWindow);
|
||||
}
|
||||
|
||||
xf_event_adjust_coordinates(xfc, &x, &y);
|
||||
|
||||
if (extended)
|
||||
freerdp_input_send_extended_mouse_event(input, flags, x, y);
|
||||
else
|
||||
freerdp_input_send_mouse_event(input, flags, x, y);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app)
|
||||
{
|
||||
if (xfc->use_xinput)
|
||||
return TRUE;
|
||||
|
||||
return xf_generic_ButtonRelease(xfc, event->xbutton.x, event->xbutton.y,
|
||||
event->xbutton.button, event->xbutton.window, app);
|
||||
return xf_generic_ButtonEvent(xfc, event->xbutton.x, event->xbutton.y,
|
||||
event->xbutton.button, event->xbutton.window, app, FALSE);
|
||||
}
|
||||
static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app)
|
||||
{
|
||||
@ -561,6 +477,9 @@ static BOOL xf_event_KeyRelease(xfContext* xfc, XEvent* event, BOOL app)
|
||||
}
|
||||
static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app)
|
||||
{
|
||||
if (!xfc->window)
|
||||
return FALSE;
|
||||
|
||||
if (event->xfocus.mode == NotifyGrab)
|
||||
return TRUE;
|
||||
|
||||
@ -644,6 +563,9 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, XEvent* event, BOOL app)
|
||||
}
|
||||
static BOOL xf_event_EnterNotify(xfContext* xfc, XEvent* event, BOOL app)
|
||||
{
|
||||
if (!xfc->window)
|
||||
return FALSE;
|
||||
|
||||
if (!app)
|
||||
{
|
||||
xfc->mouse_active = TRUE;
|
||||
@ -685,7 +607,12 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app)
|
||||
{
|
||||
Window childWindow;
|
||||
xfAppWindow* appWindow;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
rdpSettings* settings;
|
||||
|
||||
if (!xfc->window)
|
||||
return FALSE;
|
||||
|
||||
settings = xfc->context.settings;
|
||||
|
||||
if (!app)
|
||||
{
|
||||
@ -900,7 +827,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app)
|
||||
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE);
|
||||
}
|
||||
else if (!minimized && !maxVert && !maxHorz
|
||||
&& (appWindow->rail_state != WINDOW_SHOW))
|
||||
&& (appWindow->rail_state != WINDOW_SHOW) && (appWindow->rail_state != WINDOW_HIDE))
|
||||
{
|
||||
appWindow->rail_state = WINDOW_SHOW;
|
||||
xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE);
|
||||
@ -1018,10 +945,13 @@ BOOL xf_event_process(freerdp* instance, XEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (xfc->floatbar && xf_floatbar_check_event(xfc, event))
|
||||
if (xfc->window)
|
||||
{
|
||||
xf_floatbar_event_process(xfc, event);
|
||||
return TRUE;
|
||||
if (xf_floatbar_check_event(xfc->window->floatbar, event))
|
||||
{
|
||||
xf_floatbar_event_process(xfc->window->floatbar, event);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
xf_event_execute_action_script(xfc, event);
|
||||
|
||||
@ -29,12 +29,14 @@ BOOL xf_event_action_script_init(xfContext* xfc);
|
||||
void xf_event_action_script_free(xfContext* xfc);
|
||||
|
||||
BOOL xf_event_process(freerdp* instance, XEvent* event);
|
||||
void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...);
|
||||
void xf_event_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs,
|
||||
...);
|
||||
|
||||
void xf_event_adjust_coordinates(xfContext* xfc, int* x, int *y);
|
||||
void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y);
|
||||
|
||||
BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app);
|
||||
BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window window, BOOL app);
|
||||
BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window window, BOOL app);
|
||||
BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, Window window, BOOL app,
|
||||
BOOL down);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_EVENT_H */
|
||||
|
||||
@ -57,6 +57,8 @@
|
||||
#define XF_FLOATBAR_BUTTON_MINIMIZE 3
|
||||
#define XF_FLOATBAR_BUTTON_LOCKED 4
|
||||
|
||||
typedef BOOL(*OnClick)(xfFloatbar*);
|
||||
|
||||
typedef struct xf_floatbar_button xfFloatbarButton;
|
||||
|
||||
struct xf_floatbar
|
||||
@ -71,6 +73,12 @@ struct xf_floatbar
|
||||
bool locked;
|
||||
xfFloatbarButton* buttons[4];
|
||||
Window handle;
|
||||
BOOL hasCursor;
|
||||
xfContext* xfc;
|
||||
DWORD flags;
|
||||
BOOL created;
|
||||
Window root_window;
|
||||
char* title;
|
||||
};
|
||||
|
||||
struct xf_floatbar_button
|
||||
@ -84,43 +92,70 @@ struct xf_floatbar_button
|
||||
Window handle;
|
||||
};
|
||||
|
||||
static void xf_floatbar_button_onclick_close(xfContext* xfc)
|
||||
static xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type);
|
||||
|
||||
static BOOL xf_floatbar_button_onclick_close(xfFloatbar* floatbar)
|
||||
{
|
||||
ExitProcess(EXIT_SUCCESS);
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
return freerdp_abort_connect(floatbar->xfc->context.instance);
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_onclick_minimize(xfContext* xfc)
|
||||
static BOOL xf_floatbar_button_onclick_minimize(xfFloatbar* floatbar)
|
||||
{
|
||||
xfContext* xfc;
|
||||
|
||||
if (!floatbar || !floatbar->xfc)
|
||||
return FALSE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
xf_SetWindowMinimized(xfc, xfc->window);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_onclick_restore(xfContext* xfc)
|
||||
static BOOL xf_floatbar_button_onclick_restore(xfFloatbar* floatbar)
|
||||
{
|
||||
xf_toggle_fullscreen(xfc);
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
xf_toggle_fullscreen(floatbar->xfc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_onclick_locked(xfContext* xfc)
|
||||
static BOOL xf_floatbar_button_onclick_locked(xfFloatbar* floatbar)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
floatbar = xfc->window->floatbar;
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
floatbar->locked = (floatbar->locked) ? FALSE : TRUE;
|
||||
return xf_floatbar_hide_and_show(floatbar);
|
||||
}
|
||||
|
||||
void xf_floatbar_set_root_y(xfContext* xfc, int y)
|
||||
BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
floatbar = xfc->window->floatbar;
|
||||
if (!floatbar)
|
||||
return FALSE;
|
||||
|
||||
floatbar->last_motion_y_root = y;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void xf_floatbar_hide_and_show(xfContext* xfc)
|
||||
BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
floatbar = xfc->window->floatbar;
|
||||
xfContext* xfc;
|
||||
|
||||
if (!floatbar || !floatbar->xfc)
|
||||
return FALSE;
|
||||
|
||||
if (!floatbar->created)
|
||||
return TRUE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
|
||||
if (!floatbar->locked)
|
||||
{
|
||||
if ((floatbar->mode == 0) && (floatbar->last_motion_y_root > 10) &&
|
||||
if ((floatbar->mode == XF_FLOATBAR_MODE_NONE) && (floatbar->last_motion_y_root > 10) &&
|
||||
(floatbar->y > (FLOATBAR_HEIGHT * -1)))
|
||||
{
|
||||
floatbar->y = floatbar->y - 1;
|
||||
@ -132,16 +167,70 @@ void xf_floatbar_hide_and_show(xfContext* xfc)
|
||||
XMoveWindow(xfc->display, floatbar->handle, floatbar->x, floatbar->y);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible)
|
||||
static BOOL create_floatbar(xfFloatbar* floatbar)
|
||||
{
|
||||
xfContext* xfc;
|
||||
Status status;
|
||||
XWindowAttributes attr;
|
||||
|
||||
if (floatbar->created)
|
||||
return TRUE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
status = XGetWindowAttributes(xfc->display, floatbar->root_window, &attr);
|
||||
floatbar->x = attr.x + attr.width / 2 - FLOATBAR_DEFAULT_WIDTH / 2;
|
||||
floatbar->y = 0;
|
||||
|
||||
if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
|
||||
floatbar->y = -FLOATBAR_HEIGHT + 1;
|
||||
|
||||
floatbar->handle = XCreateWindow(xfc->display, floatbar->root_window,
|
||||
floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH,
|
||||
FLOATBAR_HEIGHT, 0,
|
||||
CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
|
||||
floatbar->width = FLOATBAR_DEFAULT_WIDTH;
|
||||
floatbar->height = FLOATBAR_HEIGHT;
|
||||
floatbar->mode = XF_FLOATBAR_MODE_NONE;
|
||||
floatbar->buttons[0] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_CLOSE);
|
||||
floatbar->buttons[1] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_RESTORE);
|
||||
floatbar->buttons[2] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_MINIMIZE);
|
||||
floatbar->buttons[3] = xf_floatbar_new_button(floatbar, XF_FLOATBAR_BUTTON_LOCKED);
|
||||
XSelectInput(xfc->display, floatbar->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||||
PointerMotionMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask |
|
||||
PropertyChangeMask);
|
||||
floatbar->created = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool fullscreen)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
int i, size;
|
||||
floatbar = xfc->window->floatbar;
|
||||
bool visible = False;
|
||||
xfContext* xfc;
|
||||
|
||||
if (!floatbar || !floatbar->xfc)
|
||||
return FALSE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
|
||||
/* Only visible if enabled */
|
||||
if (floatbar->flags & 0x0001)
|
||||
{
|
||||
/* Visible if fullscreen and flag visible in fullscreen mode */
|
||||
visible |= ((floatbar->flags & 0x0010) != 0) && fullscreen;
|
||||
/* Visible if window and flag visible in window mode */
|
||||
visible |= ((floatbar->flags & 0x0020) != 0) && !fullscreen;
|
||||
}
|
||||
|
||||
if (visible)
|
||||
{
|
||||
if (!create_floatbar(floatbar))
|
||||
return FALSE;
|
||||
|
||||
XMapWindow(xfc->display, floatbar->handle);
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
@ -149,15 +238,23 @@ void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible)
|
||||
{
|
||||
XMapWindow(xfc->display, floatbar->buttons[i]->handle);
|
||||
}
|
||||
|
||||
/* If default is hidden (and not sticky) don't show on fullscreen state changes */
|
||||
if (((floatbar->flags & 0x0004) == 0) && !floatbar->locked)
|
||||
floatbar->y = -FLOATBAR_HEIGHT + 1;
|
||||
|
||||
xf_floatbar_hide_and_show(floatbar);
|
||||
}
|
||||
else
|
||||
else if (floatbar->created)
|
||||
{
|
||||
XUnmapSubwindows(xfc->display, floatbar->handle);
|
||||
XUnmapWindow(xfc->display, floatbar->handle);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static xfFloatbarButton* xf_floatbar_new_button(xfContext* xfc, xfFloatbar* floatbar, int type)
|
||||
xfFloatbarButton* xf_floatbar_new_button(xfFloatbar* floatbar, int type)
|
||||
{
|
||||
xfFloatbarButton* button;
|
||||
button = (xfFloatbarButton*) calloc(1, sizeof(xfFloatbarButton));
|
||||
@ -191,74 +288,74 @@ static xfFloatbarButton* xf_floatbar_new_button(xfContext* xfc, xfFloatbar* floa
|
||||
|
||||
button->y = 0;
|
||||
button->focus = FALSE;
|
||||
button->handle = XCreateWindow(xfc->display, floatbar->handle, button->x, 0, FLOATBAR_BUTTON_WIDTH,
|
||||
button->handle = XCreateWindow(floatbar->xfc->display, floatbar->handle, button->x, 0,
|
||||
FLOATBAR_BUTTON_WIDTH,
|
||||
FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
|
||||
XSelectInput(xfc->display, button->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||||
XSelectInput(floatbar->xfc->display, button->handle,
|
||||
ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||||
FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask);
|
||||
return button;
|
||||
}
|
||||
|
||||
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window)
|
||||
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* name, DWORD flags)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
XWindowAttributes attr;
|
||||
int i, width;
|
||||
|
||||
/* Floatbar not enabled */
|
||||
if ((flags & 0x0001) == 0)
|
||||
return NULL;
|
||||
|
||||
if (!xfc)
|
||||
return NULL;
|
||||
|
||||
/* Force disable with remote app */
|
||||
if (xfc->remote_app)
|
||||
return NULL;
|
||||
|
||||
floatbar = (xfFloatbar*) calloc(1, sizeof(xfFloatbar));
|
||||
floatbar->locked = TRUE;
|
||||
XGetWindowAttributes(xfc->display, window, &attr);
|
||||
|
||||
for (i = 0; i < xfc->vscreen.nmonitors; i++)
|
||||
{
|
||||
if (attr.x >= xfc->vscreen.monitors[i].area.left && attr.x <= xfc->vscreen.monitors[i].area.right)
|
||||
{
|
||||
width = xfc->vscreen.monitors[i].area.right - xfc->vscreen.monitors[i].area.left;
|
||||
floatbar->x = width / 2 + xfc->vscreen.monitors[i].area.left - FLOATBAR_DEFAULT_WIDTH / 2;
|
||||
}
|
||||
}
|
||||
if (!floatbar)
|
||||
return NULL;
|
||||
|
||||
floatbar->y = 0;
|
||||
floatbar->handle = XCreateWindow(xfc->display, window, floatbar->x, 0, FLOATBAR_DEFAULT_WIDTH,
|
||||
FLOATBAR_HEIGHT, 0,
|
||||
CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
|
||||
floatbar->width = FLOATBAR_DEFAULT_WIDTH;
|
||||
floatbar->height = FLOATBAR_HEIGHT;
|
||||
floatbar->mode = XF_FLOATBAR_MODE_NONE;
|
||||
floatbar->buttons[0] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_CLOSE);
|
||||
floatbar->buttons[1] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_RESTORE);
|
||||
floatbar->buttons[2] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_MINIMIZE);
|
||||
floatbar->buttons[3] = xf_floatbar_new_button(xfc, floatbar, XF_FLOATBAR_BUTTON_LOCKED);
|
||||
XSelectInput(xfc->display, floatbar->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask |
|
||||
PointerMotionMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask |
|
||||
PropertyChangeMask);
|
||||
floatbar->title = _strdup(name);
|
||||
|
||||
if (!floatbar->title)
|
||||
goto fail;
|
||||
|
||||
floatbar->root_window = window;
|
||||
floatbar->flags = flags;
|
||||
floatbar->xfc = xfc;
|
||||
floatbar->locked = flags & 0x0002;
|
||||
xf_floatbar_toggle_fullscreen(floatbar, FALSE);
|
||||
return floatbar;
|
||||
fail:
|
||||
xf_floatbar_free(floatbar);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned long xf_floatbar_get_color(xfContext* xfc, char* rgb_value)
|
||||
static unsigned long xf_floatbar_get_color(xfFloatbar* floatbar, char* rgb_value)
|
||||
{
|
||||
Colormap cmap;
|
||||
XColor color;
|
||||
cmap = DefaultColormap(xfc->display, XDefaultScreen(xfc->display));
|
||||
XParseColor(xfc->display, cmap, rgb_value, &color);
|
||||
XAllocColor(xfc->display, cmap, &color);
|
||||
XFreeColormap(xfc->display, cmap);
|
||||
Display* display = floatbar->xfc->display;
|
||||
cmap = DefaultColormap(display, XDefaultScreen(display));
|
||||
XParseColor(display, cmap, rgb_value, &color);
|
||||
XAllocColor(display, cmap, &color);
|
||||
XFreeColormap(display, cmap);
|
||||
return color.pixel;
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_expose(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_event_expose(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
GC gc, shape_gc;
|
||||
Pixmap pmap;
|
||||
XPoint shape[5], border[5];
|
||||
xfFloatbar* floatbar;
|
||||
int len;
|
||||
floatbar = xfc->window->floatbar;
|
||||
Display* display = floatbar->xfc->display;
|
||||
/* create the pixmap that we'll use for shaping the window */
|
||||
pmap = XCreatePixmap(xfc->display, floatbar->handle, floatbar->width, floatbar->height, 1);
|
||||
gc = XCreateGC(xfc->display, floatbar->handle, 0, 0);
|
||||
shape_gc = XCreateGC(xfc->display, pmap, 0, 0);
|
||||
pmap = XCreatePixmap(display, floatbar->handle, floatbar->width, floatbar->height, 1);
|
||||
gc = XCreateGC(display, floatbar->handle, 0, 0);
|
||||
shape_gc = XCreateGC(display, pmap, 0, 0);
|
||||
/* points for drawing the floatbar */
|
||||
shape[0].x = 0;
|
||||
shape[0].y = 0;
|
||||
@ -282,34 +379,32 @@ static void xf_floatbar_event_expose(xfContext* xfc, XEvent* event)
|
||||
border[4].x = border[0].x;
|
||||
border[4].y = border[0].y;
|
||||
/* Fill all pixels with 0 */
|
||||
XSetForeground(xfc->display, shape_gc, 0);
|
||||
XFillRectangle(xfc->display, pmap, shape_gc, 0, 0, floatbar->width,
|
||||
XSetForeground(display, shape_gc, 0);
|
||||
XFillRectangle(display, pmap, shape_gc, 0, 0, floatbar->width,
|
||||
floatbar->height);
|
||||
/* Fill all pixels which should be shown with 1 */
|
||||
XSetForeground(xfc->display, shape_gc, 1);
|
||||
XFillPolygon(xfc->display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin);
|
||||
XShapeCombineMask(xfc->display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet);
|
||||
XSetForeground(display, shape_gc, 1);
|
||||
XFillPolygon(display, pmap, shape_gc, shape, 5, 0, CoordModeOrigin);
|
||||
XShapeCombineMask(display, floatbar->handle, ShapeBounding, 0, 0, pmap, ShapeSet);
|
||||
/* draw the float bar */
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BACKGROUND));
|
||||
XFillPolygon(xfc->display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin);
|
||||
XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
|
||||
XFillPolygon(display, floatbar->handle, gc, shape, 4, 0, CoordModeOrigin);
|
||||
/* draw an border for the floatbar */
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BORDER));
|
||||
XDrawLines(xfc->display, floatbar->handle, gc, border, 5, CoordModeOrigin);
|
||||
XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
|
||||
XDrawLines(display, floatbar->handle, gc, border, 5, CoordModeOrigin);
|
||||
/* draw the host name connected to */
|
||||
len = strlen(xfc->context.settings->ServerHostname);
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_FOREGROUND));
|
||||
XDrawString(xfc->display, floatbar->handle, gc, floatbar->width / 2 - len * 2, 15,
|
||||
xfc->context.settings->ServerHostname, len);
|
||||
XFreeGC(xfc->display, gc);
|
||||
XFreeGC(xfc->display, shape_gc);
|
||||
len = strlen(floatbar->title);
|
||||
XSetForeground(display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
|
||||
XDrawString(display, floatbar->handle, gc, floatbar->width / 2 - len * 2, 15,
|
||||
floatbar->title, len);
|
||||
XFreeGC(display, gc);
|
||||
XFreeGC(display, shape_gc);
|
||||
}
|
||||
|
||||
static xfFloatbarButton* xf_floatbar_get_button(xfContext* xfc, XEvent* event)
|
||||
static xfFloatbarButton* xf_floatbar_get_button(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
int i, size;
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
floatbar = xfc->window->floatbar;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
@ -322,12 +417,11 @@ static xfFloatbarButton* xf_floatbar_get_button(xfContext* xfc, XEvent* event)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_update_positon(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_button_update_positon(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
xfFloatbarButton* button;
|
||||
int i, size;
|
||||
floatbar = xfc->window->floatbar;
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
@ -353,18 +447,17 @@ static void xf_floatbar_button_update_positon(xfContext* xfc, XEvent* event)
|
||||
}
|
||||
|
||||
XMoveWindow(xfc->display, button->handle, button->x, button->y);
|
||||
xf_floatbar_event_expose(xfc, event);
|
||||
xf_floatbar_event_expose(floatbar, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_expose(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
xfFloatbarButton* button;
|
||||
xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event);
|
||||
static unsigned char* bits;
|
||||
GC gc;
|
||||
Pixmap pattern;
|
||||
button = xf_floatbar_get_button(xfc, event);
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
|
||||
if (!button)
|
||||
return;
|
||||
@ -402,43 +495,39 @@ static void xf_floatbar_button_event_expose(xfContext* xfc, XEvent* event)
|
||||
FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH);
|
||||
|
||||
if (!(button->focus))
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BACKGROUND));
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BACKGROUND));
|
||||
else
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_BORDER));
|
||||
XSetForeground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_BORDER));
|
||||
|
||||
XSetBackground(xfc->display, gc, xf_floatbar_get_color(xfc, FLOATBAR_COLOR_FOREGROUND));
|
||||
XSetBackground(xfc->display, gc, xf_floatbar_get_color(floatbar, FLOATBAR_COLOR_FOREGROUND));
|
||||
XCopyPlane(xfc->display, pattern, button->handle, gc, 0, 0, FLOATBAR_BUTTON_WIDTH,
|
||||
FLOATBAR_BUTTON_WIDTH, 0, 0, 1);
|
||||
XFreePixmap(xfc->display, pattern);
|
||||
XFreeGC(xfc->display, gc);
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_buttonpress(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_button_event_buttonpress(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button;
|
||||
button = xf_floatbar_get_button(xfc, event);
|
||||
xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event);
|
||||
|
||||
if (button)
|
||||
button->clicked = TRUE;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_buttonrelease(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_button_event_buttonrelease(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button;
|
||||
button = xf_floatbar_get_button(xfc, event);
|
||||
button = xf_floatbar_get_button(floatbar, event);
|
||||
|
||||
if (button)
|
||||
{
|
||||
if (button->clicked)
|
||||
button->onclick(xfc);
|
||||
button->onclick(floatbar);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_buttonpress(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
floatbar = xfc->window->floatbar;
|
||||
|
||||
switch (event->xbutton.button)
|
||||
{
|
||||
case Button1:
|
||||
@ -456,12 +545,12 @@ static void xf_floatbar_event_buttonpress(xfContext* xfc, XEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_buttonrelease(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_event_buttonrelease(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
switch (event->xbutton.button)
|
||||
{
|
||||
case Button1:
|
||||
xfc->window->floatbar->mode = XF_FLOATBAR_MODE_NONE;
|
||||
floatbar->mode = XF_FLOATBAR_MODE_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -469,11 +558,10 @@ static void xf_floatbar_event_buttonrelease(xfContext* xfc, XEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_resize(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_resize(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
floatbar = xfc->window->floatbar;
|
||||
int x, width, movement;
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
/* calculate movement which happened on the root window */
|
||||
movement = event->xmotion.x_root - floatbar->last_motion_x_root;
|
||||
|
||||
@ -498,11 +586,10 @@ static void xf_floatbar_resize(xfContext* xfc, XEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_dragging(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_dragging(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
floatbar = xfc->window->floatbar;
|
||||
int x, movement;
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
/* calculate movement and new x position */
|
||||
movement = event->xmotion.x_root - floatbar->last_motion_x_root;
|
||||
x = floatbar->x + movement;
|
||||
@ -518,78 +605,82 @@ static void xf_floatbar_dragging(xfContext* xfc, XEvent* event)
|
||||
floatbar->x = x;
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_motionnotify(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_event_motionnotify(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
int mode;
|
||||
xfFloatbar* floatbar;
|
||||
Cursor cursor;
|
||||
mode = xfc->window->floatbar->mode;
|
||||
floatbar = xfc->window->floatbar;
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
mode = floatbar->mode;
|
||||
cursor = XCreateFontCursor(xfc->display, XC_arrow);
|
||||
|
||||
if ((event->xmotion.state & Button1Mask) && (mode > XF_FLOATBAR_MODE_DRAGGING))
|
||||
{
|
||||
xf_floatbar_resize(xfc, event);
|
||||
xf_floatbar_resize(floatbar, event);
|
||||
}
|
||||
else if ((event->xmotion.state & Button1Mask) && (mode == XF_FLOATBAR_MODE_DRAGGING))
|
||||
{
|
||||
xf_floatbar_dragging(xfc, event);
|
||||
xf_floatbar_dragging(floatbar, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (event->xmotion.x <= FLOATBAR_BORDER ||
|
||||
event->xmotion.x >= xfc->window->floatbar->width - FLOATBAR_BORDER)
|
||||
event->xmotion.x >= floatbar->width - FLOATBAR_BORDER)
|
||||
cursor = XCreateFontCursor(xfc->display, XC_sb_h_double_arrow);
|
||||
}
|
||||
|
||||
XDefineCursor(xfc->display, xfc->window->handle, cursor);
|
||||
XFreeCursor(xfc->display, cursor);
|
||||
xfc->window->floatbar->last_motion_x_root = event->xmotion.x_root;
|
||||
floatbar->last_motion_x_root = event->xmotion.x_root;
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_focusin(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button;
|
||||
button = xf_floatbar_get_button(xfc, event);
|
||||
button = xf_floatbar_get_button(floatbar, event);
|
||||
|
||||
if (button)
|
||||
{
|
||||
button->focus = TRUE;
|
||||
xf_floatbar_button_event_expose(xfc, event);
|
||||
xf_floatbar_button_event_expose(floatbar, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_button_event_focusout(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbarButton* button;
|
||||
button = xf_floatbar_get_button(xfc, event);
|
||||
button = xf_floatbar_get_button(floatbar, event);
|
||||
|
||||
if (button)
|
||||
{
|
||||
button->focus = FALSE;
|
||||
button->clicked = FALSE;
|
||||
xf_floatbar_button_event_expose(xfc, event);
|
||||
xf_floatbar_button_event_expose(floatbar, event);
|
||||
}
|
||||
}
|
||||
|
||||
static void xf_floatbar_event_focusout(xfContext* xfc, XEvent* event)
|
||||
static void xf_floatbar_event_focusout(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
Cursor cursor;
|
||||
cursor = XCreateFontCursor(xfc->display, XC_arrow);
|
||||
XDefineCursor(xfc->display, xfc->window->handle, cursor);
|
||||
XFreeCursor(xfc->display, cursor);
|
||||
xfContext* xfc = floatbar->xfc;
|
||||
|
||||
if (xfc->pointer)
|
||||
{
|
||||
XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event)
|
||||
BOOL xf_floatbar_check_event(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
xfFloatbarButton* button;
|
||||
size_t i, size;
|
||||
xfContext* xfc;
|
||||
|
||||
if (!xfc || !event || !xfc->window)
|
||||
if (!floatbar || !floatbar->xfc || !event)
|
||||
return FALSE;
|
||||
|
||||
floatbar = xfc->window->floatbar;
|
||||
if (!floatbar->created)
|
||||
return FALSE;
|
||||
|
||||
xfc = floatbar->xfc;
|
||||
|
||||
if (event->xany.window == floatbar->handle)
|
||||
return TRUE;
|
||||
@ -607,70 +698,69 @@ BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL xf_floatbar_event_process(xfContext* xfc, XEvent* event)
|
||||
BOOL xf_floatbar_event_process(xfFloatbar* floatbar, XEvent* event)
|
||||
{
|
||||
xfFloatbar* floatbar;
|
||||
|
||||
if (!xfc || !xfc->window || !event)
|
||||
if (!floatbar || !floatbar->xfc || !event)
|
||||
return FALSE;
|
||||
|
||||
floatbar = xfc->window->floatbar;
|
||||
if (!floatbar->created)
|
||||
return FALSE;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case Expose:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_expose(xfc, event);
|
||||
xf_floatbar_event_expose(floatbar, event);
|
||||
else
|
||||
xf_floatbar_button_event_expose(xfc, event);
|
||||
xf_floatbar_button_event_expose(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
xf_floatbar_event_motionnotify(xfc, event);
|
||||
xf_floatbar_event_motionnotify(floatbar, event);
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_buttonpress(xfc, event);
|
||||
xf_floatbar_event_buttonpress(floatbar, event);
|
||||
else
|
||||
xf_floatbar_button_event_buttonpress(xfc, event);
|
||||
xf_floatbar_button_event_buttonpress(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_buttonrelease(xfc, event);
|
||||
xf_floatbar_event_buttonrelease(floatbar, event);
|
||||
else
|
||||
xf_floatbar_button_event_buttonrelease(xfc, event);
|
||||
xf_floatbar_button_event_buttonrelease(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
case FocusIn:
|
||||
if (event->xany.window != floatbar->handle)
|
||||
xf_floatbar_button_event_focusin(xfc, event);
|
||||
xf_floatbar_button_event_focusin(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
case FocusOut:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_event_focusout(xfc, event);
|
||||
xf_floatbar_event_focusout(floatbar, event);
|
||||
else
|
||||
xf_floatbar_button_event_focusout(xfc, event);
|
||||
xf_floatbar_button_event_focusout(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
case ConfigureNotify:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_button_update_positon(xfc, event);
|
||||
xf_floatbar_button_update_positon(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
if (event->xany.window == floatbar->handle)
|
||||
xf_floatbar_button_update_positon(xfc, event);
|
||||
xf_floatbar_button_update_positon(floatbar, event);
|
||||
|
||||
break;
|
||||
|
||||
@ -695,16 +785,17 @@ static void xf_floatbar_button_free(xfContext* xfc, xfFloatbarButton* button)
|
||||
free(button);
|
||||
}
|
||||
|
||||
void xf_floatbar_free(xfContext* xfc, xfWindow* window, xfFloatbar* floatbar)
|
||||
void xf_floatbar_free(xfFloatbar* floatbar)
|
||||
{
|
||||
size_t i, size;
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
xfContext* xfc;
|
||||
|
||||
if (!floatbar)
|
||||
return;
|
||||
|
||||
if (window->floatbar == floatbar)
|
||||
window->floatbar = NULL;
|
||||
free(floatbar->title);
|
||||
xfc = floatbar->xfc;
|
||||
size = ARRAYSIZE(floatbar->buttons);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
|
||||
@ -22,13 +22,13 @@ typedef struct xf_floatbar xfFloatbar;
|
||||
|
||||
#include "xfreerdp.h"
|
||||
|
||||
typedef void(*OnClick)(xfContext*);
|
||||
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window);
|
||||
BOOL xf_floatbar_event_process(xfContext* xfc, XEvent* event);
|
||||
BOOL xf_floatbar_check_event(xfContext* xfc, XEvent* event);
|
||||
void xf_floatbar_toggle_visibility(xfContext* xfc, bool visible);
|
||||
void xf_floatbar_free(xfContext* xfc, xfWindow* window, xfFloatbar* floatbar);
|
||||
void xf_floatbar_hide_and_show(xfContext* xfc);
|
||||
void xf_floatbar_set_root_y(xfContext* xfc, int y);
|
||||
xfFloatbar* xf_floatbar_new(xfContext* xfc, Window window, const char* title, DWORD flags);
|
||||
void xf_floatbar_free(xfFloatbar* floatbar);
|
||||
|
||||
BOOL xf_floatbar_event_process(xfFloatbar* floatbar, XEvent* event);
|
||||
BOOL xf_floatbar_check_event(xfFloatbar* floatbar, XEvent* event);
|
||||
BOOL xf_floatbar_toggle_fullscreen(xfFloatbar* floatbar, bool visible);
|
||||
BOOL xf_floatbar_hide_and_show(xfFloatbar* floatbar);
|
||||
BOOL xf_floatbar_set_root_y(xfFloatbar* floatbar, int y);
|
||||
|
||||
#endif /* FREERDP_CLIENT_X11_FLOATBAR_H */
|
||||
|
||||
@ -129,6 +129,7 @@ static UINT xf_UpdateSurfaces(RdpgfxClientContext* context)
|
||||
if (gdi->suppressOutput)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
EnterCriticalSection(&context->mux);
|
||||
context->GetSurfaceIds(context, &pSurfaceIds, &count);
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
@ -145,6 +146,7 @@ static UINT xf_UpdateSurfaces(RdpgfxClientContext* context)
|
||||
}
|
||||
|
||||
free(pSurfaceIds);
|
||||
LeaveCriticalSection(&context->mux);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -153,7 +155,7 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y,
|
||||
{
|
||||
UINT16 count;
|
||||
UINT32 index;
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
UINT status = ERROR_INTERNAL_ERROR;
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
RECTANGLE_16 surfaceRect;
|
||||
@ -164,7 +166,12 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y,
|
||||
invalidRect.top = y;
|
||||
invalidRect.right = x + width;
|
||||
invalidRect.bottom = y + height;
|
||||
context->GetSurfaceIds(context, &pSurfaceIds, &count);
|
||||
status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
goto fail;
|
||||
|
||||
EnterCriticalSection(&context->mux);
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
@ -192,7 +199,13 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y,
|
||||
}
|
||||
|
||||
free(pSurfaceIds);
|
||||
LeaveCriticalSection(&context->mux);
|
||||
IFCALLRET(context->UpdateSurfaces, status, context);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -343,6 +356,8 @@ static UINT xf_DeleteSurface(RdpgfxClientContext* context,
|
||||
{
|
||||
rdpCodecs* codecs = NULL;
|
||||
xfGfxSurface* surface = NULL;
|
||||
UINT status;
|
||||
EnterCriticalSection(&context->mux);
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context,
|
||||
deleteSurface->surfaceId);
|
||||
|
||||
@ -360,13 +375,14 @@ static UINT xf_DeleteSurface(RdpgfxClientContext* context,
|
||||
free(surface);
|
||||
}
|
||||
|
||||
context->SetSurfaceData(context, deleteSurface->surfaceId, NULL);
|
||||
status = context->SetSurfaceData(context, deleteSurface->surfaceId, NULL);
|
||||
|
||||
if (codecs && codecs->progressive)
|
||||
progressive_delete_surface_context(codecs->progressive,
|
||||
deleteSurface->surfaceId);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
LeaveCriticalSection(&context->mux);
|
||||
return status;
|
||||
}
|
||||
|
||||
void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx)
|
||||
|
||||
@ -581,13 +581,13 @@ static int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype)
|
||||
switch (evtype)
|
||||
{
|
||||
case XI_ButtonPress:
|
||||
xf_generic_ButtonPress(xfc, (int) event->event_x, (int) event->event_y,
|
||||
event->detail, event->event, xfc->remote_app);
|
||||
xf_generic_ButtonEvent(xfc, (int) event->event_x, (int) event->event_y,
|
||||
event->detail, event->event, xfc->remote_app, TRUE);
|
||||
break;
|
||||
|
||||
case XI_ButtonRelease:
|
||||
xf_generic_ButtonRelease(xfc, (int) event->event_x, (int) event->event_y,
|
||||
event->detail, event->event, xfc->remote_app);
|
||||
xf_generic_ButtonEvent(xfc, (int) event->event_x, (int) event->event_y,
|
||||
event->detail, event->event, xfc->remote_app, FALSE);
|
||||
break;
|
||||
|
||||
case XI_Motion:
|
||||
|
||||
@ -141,7 +141,7 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
int monitor_index = 0;
|
||||
BOOL primaryMonitorFound = FALSE;
|
||||
VIRTUAL_SCREEN* vscreen;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
rdpSettings* settings;
|
||||
int mouse_x, mouse_y, _dummy_i;
|
||||
Window _dummy_w;
|
||||
int current_monitor = 0;
|
||||
@ -154,6 +154,11 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
XRRMonitorInfo* rrmonitors = NULL;
|
||||
BOOL useXRandr = FALSE;
|
||||
#endif
|
||||
|
||||
if (!xfc || !pMaxWidth || !pMaxHeight || !xfc->context.settings)
|
||||
return FALSE;
|
||||
|
||||
settings = xfc->context.settings;
|
||||
vscreen = &xfc->vscreen;
|
||||
*pMaxWidth = settings->DesktopWidth;
|
||||
*pMaxHeight = settings->DesktopHeight;
|
||||
@ -274,6 +279,9 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
if (settings->NumMonitorIds == 1)
|
||||
{
|
||||
monitor = vscreen->monitors + current_monitor;
|
||||
if (!monitor)
|
||||
return FALSE;
|
||||
|
||||
xfc->workArea.x = monitor->area.left;
|
||||
xfc->workArea.y = monitor->area.top;
|
||||
xfc->workArea.width = monitor->area.right - monitor->area.left + 1;
|
||||
@ -305,6 +313,9 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
*/
|
||||
if (vscreen->nmonitors > 0)
|
||||
{
|
||||
if (!vscreen->monitors)
|
||||
return FALSE;
|
||||
|
||||
*pMaxWidth = vscreen->monitors[current_monitor].area.right -
|
||||
vscreen->monitors[current_monitor].area.left + 1;
|
||||
*pMaxHeight = vscreen->monitors[current_monitor].area.bottom -
|
||||
@ -346,12 +357,15 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
if (!xf_is_monitor_id_active(xfc, i))
|
||||
continue;
|
||||
|
||||
if (!vscreen->monitors)
|
||||
return FALSE;
|
||||
|
||||
settings->MonitorDefArray[nmonitors].x = vscreen->monitors[i].area.left;
|
||||
settings->MonitorDefArray[nmonitors].y = vscreen->monitors[i].area.top;
|
||||
settings->MonitorDefArray[nmonitors].width =
|
||||
MIN(vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1, *pMaxWidth);
|
||||
vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1;
|
||||
settings->MonitorDefArray[nmonitors].height =
|
||||
MIN(vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1, *pMaxHeight);
|
||||
vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1;
|
||||
settings->MonitorDefArray[nmonitors].orig_screen = i;
|
||||
#ifdef USABLE_XRANDR
|
||||
|
||||
@ -380,7 +394,10 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
|
||||
/* If no monitor is active(bogus command-line monitor specification) - then lets try to fallback to go fullscreen on the current monitor only */
|
||||
if (nmonitors == 0 && vscreen->nmonitors > 0)
|
||||
{
|
||||
{
|
||||
if (!vscreen->monitors)
|
||||
return FALSE;
|
||||
|
||||
settings->MonitorDefArray[0].x = vscreen->monitors[current_monitor].area.left;
|
||||
settings->MonitorDefArray[0].y = vscreen->monitors[current_monitor].area.top;
|
||||
settings->MonitorDefArray[0].width = MIN(
|
||||
@ -509,8 +526,8 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
}
|
||||
|
||||
/* Set the desktop width and height according to the bounding rectangle around the active monitors */
|
||||
*pMaxWidth = vscreen->area.right - vscreen->area.left + 1;
|
||||
*pMaxHeight = vscreen->area.bottom - vscreen->area.top + 1;
|
||||
*pMaxWidth = MIN(*pMaxWidth, vscreen->area.right - vscreen->area.left + 1);
|
||||
*pMaxHeight = MIN(*pMaxHeight, vscreen->area.bottom - vscreen->area.top + 1);
|
||||
}
|
||||
|
||||
/* some 2008 server freeze at logon if we announce support for monitor layout PDU with
|
||||
|
||||
@ -222,8 +222,7 @@ static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion)
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows,
|
||||
(void*) pKeys[index]);
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*)pKeys[index]);
|
||||
|
||||
if (appWindow)
|
||||
{
|
||||
@ -327,14 +326,12 @@ static BOOL xf_rail_window_common(rdpContext* context,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HashTable_Add(xfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId,
|
||||
(void*) appWindow);
|
||||
HashTable_Add(xfc->railWindows, &appWindow->windowId, (void*) appWindow);
|
||||
xf_AppWindowInit(xfc, appWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows,
|
||||
(void*)(UINT_PTR) orderInfo->windowId);
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, &orderInfo->windowId);
|
||||
}
|
||||
|
||||
if (!appWindow)
|
||||
@ -544,7 +541,7 @@ static BOOL xf_rail_window_delete(rdpContext* context,
|
||||
if (!xfc)
|
||||
return FALSE;
|
||||
|
||||
HashTable_Remove(xfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId);
|
||||
HashTable_Remove(xfc->railWindows, &orderInfo->windowId);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -809,8 +806,7 @@ static void xf_rail_set_window_icon(xfContext* xfc,
|
||||
|
||||
static xfAppWindow* xf_rail_get_window_by_id(xfContext* xfc, UINT32 windowId)
|
||||
{
|
||||
return (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows,
|
||||
(void*)(UINT_PTR) windowId);
|
||||
return (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, &windowId);
|
||||
}
|
||||
|
||||
static BOOL xf_rail_window_icon(rdpContext* context,
|
||||
@ -999,17 +995,24 @@ static UINT xf_rail_server_system_param(RailClientContext* context,
|
||||
static UINT xf_rail_server_handshake(RailClientContext* context,
|
||||
const RAIL_HANDSHAKE_ORDER* handshake)
|
||||
{
|
||||
RAIL_EXEC_ORDER exec;
|
||||
RAIL_SYSPARAM_ORDER sysparam;
|
||||
UINT status;
|
||||
RAIL_EXEC_ORDER exec = { 0 };
|
||||
RAIL_SYSPARAM_ORDER sysparam = { 0 };
|
||||
RAIL_HANDSHAKE_ORDER clientHandshake;
|
||||
RAIL_CLIENT_STATUS_ORDER clientStatus;
|
||||
RAIL_CLIENT_STATUS_ORDER clientStatus = { 0 };
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
rdpSettings* settings = xfc->context.settings;
|
||||
clientHandshake.buildNumber = 0x00001DB0;
|
||||
context->ClientHandshake(context, &clientHandshake);
|
||||
ZeroMemory(&clientStatus, sizeof(RAIL_CLIENT_STATUS_ORDER));
|
||||
status = context->ClientHandshake(context, &clientHandshake);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
return status;
|
||||
|
||||
clientStatus.flags = RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE;
|
||||
context->ClientInformation(context, &clientStatus);
|
||||
status = context->ClientInformation(context, &clientStatus);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
return status;
|
||||
|
||||
if (settings->RemoteAppLanguageBarSupported)
|
||||
{
|
||||
@ -1018,7 +1021,6 @@ static UINT xf_rail_server_handshake(RailClientContext* context,
|
||||
context->ClientLanguageBarInfo(context, &langBarInfo);
|
||||
}
|
||||
|
||||
ZeroMemory(&sysparam, sizeof(RAIL_SYSPARAM_ORDER));
|
||||
sysparam.params = 0;
|
||||
sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST;
|
||||
sysparam.highContrast.colorScheme.string = NULL;
|
||||
@ -1038,13 +1040,15 @@ static UINT xf_rail_server_handshake(RailClientContext* context,
|
||||
sysparam.workArea.right = settings->DesktopWidth;
|
||||
sysparam.workArea.bottom = settings->DesktopHeight;
|
||||
sysparam.dragFullWindows = FALSE;
|
||||
context->ClientSystemParam(context, &sysparam);
|
||||
ZeroMemory(&exec, sizeof(RAIL_EXEC_ORDER));
|
||||
status = context->ClientSystemParam(context, &sysparam);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
return status;
|
||||
|
||||
exec.RemoteApplicationProgram = settings->RemoteApplicationProgram;
|
||||
exec.RemoteApplicationWorkingDir = settings->ShellWorkingDirectory;
|
||||
exec.RemoteApplicationArguments = settings->RemoteApplicationCmdLine;
|
||||
context->ClientExecute(context, &exec);
|
||||
return CHANNEL_RC_OK;
|
||||
return context->ClientExecute(context, &exec);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1072,7 +1076,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context,
|
||||
xfAppWindow* appWindow = NULL;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows,
|
||||
(void*)(UINT_PTR) localMoveSize->windowId);
|
||||
(void*)&localMoveSize->windowId);
|
||||
|
||||
if (!appWindow)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
@ -1167,8 +1171,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context,
|
||||
{
|
||||
xfAppWindow* appWindow = NULL;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows,
|
||||
(void*)(UINT_PTR) minMaxInfo->windowId);
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*)&minMaxInfo->windowId);
|
||||
|
||||
if (appWindow)
|
||||
{
|
||||
@ -1204,6 +1207,16 @@ static UINT xf_rail_server_get_appid_response(RailClientContext* context,
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL rail_window_key_equals(void* key1, void* key2)
|
||||
{
|
||||
return *(UINT32*)key1 == *(UINT32*)key2;
|
||||
}
|
||||
|
||||
static UINT32 rail_window_key_hash(void* key)
|
||||
{
|
||||
return *(UINT32*)key;
|
||||
}
|
||||
|
||||
static void rail_window_free(void* value)
|
||||
{
|
||||
xfAppWindow* appWindow = (xfAppWindow*) value;
|
||||
@ -1237,6 +1250,8 @@ int xf_rail_init(xfContext* xfc, RailClientContext* rail)
|
||||
if (!xfc->railWindows)
|
||||
return 0;
|
||||
|
||||
xfc->railWindows->keyCompare = rail_window_key_equals;
|
||||
xfc->railWindows->hash = rail_window_key_hash;
|
||||
xfc->railWindows->valueFree = rail_window_free;
|
||||
xfc->railIconCache = RailIconCache_New(xfc->context.settings);
|
||||
|
||||
|
||||
@ -163,9 +163,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen)
|
||||
/* show/hide decorations (e.g. title bar) as guided by xfc->decorations */
|
||||
xf_SetWindowDecorations(xfc, window->handle, window->decorations);
|
||||
DEBUG_X11(TAG, "X window decoration set to %d", (int)window->decorations);
|
||||
|
||||
if (xfc->floatbar)
|
||||
xf_floatbar_toggle_visibility(xfc, fullscreen);
|
||||
xf_floatbar_toggle_fullscreen(xfc->window->floatbar, fullscreen);
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
@ -587,7 +585,7 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width,
|
||||
settings->DesktopPosY);
|
||||
}
|
||||
|
||||
window->floatbar = xf_floatbar_new(xfc, window->handle);
|
||||
window->floatbar = xf_floatbar_new(xfc, window->handle, name, settings->Floatbar);
|
||||
return window;
|
||||
}
|
||||
|
||||
@ -636,8 +634,7 @@ void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window)
|
||||
if (xfc->window == window)
|
||||
xfc->window = NULL;
|
||||
|
||||
if (window->floatbar)
|
||||
xf_floatbar_free(xfc, window, window->floatbar);
|
||||
xf_floatbar_free(window->floatbar);
|
||||
|
||||
if (window->gc)
|
||||
XFreeGC(xfc->display, window->gc);
|
||||
@ -988,6 +985,8 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state)
|
||||
if (appWindow->is_transient)
|
||||
xf_SetWindowUnlisted(xfc, appWindow->handle);
|
||||
|
||||
XMapWindow(xfc->display, appWindow->handle);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1118,8 +1117,7 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd)
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows,
|
||||
(void*) pKeys[index]);
|
||||
appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, (void*) pKeys[index]);
|
||||
|
||||
if (appWindow->handle == wnd)
|
||||
{
|
||||
|
||||
@ -85,13 +85,14 @@ typedef struct _xfDispContext xfDispContext;
|
||||
typedef struct _xfVideoContext xfVideoContext;
|
||||
typedef struct xf_rail_icon_cache xfRailIconCache;
|
||||
|
||||
/* Value of the first logical button number in X11 which must be */
|
||||
/* subtracted to go from a button number in X11 to an index into */
|
||||
/* a per-button array. */
|
||||
#define BUTTON_BASE Button1
|
||||
|
||||
/* Number of buttons that are mapped from X11 to RDP button events. */
|
||||
#define NUM_BUTTONS_MAPPED 3
|
||||
#define NUM_BUTTONS_MAPPED 11
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int button;
|
||||
UINT16 flags;
|
||||
} button_map;
|
||||
|
||||
struct xf_context
|
||||
{
|
||||
@ -161,7 +162,6 @@ struct xf_context
|
||||
BOOL use_xinput;
|
||||
BOOL mouse_active;
|
||||
BOOL fullscreen_toggle;
|
||||
BOOL floatbar;
|
||||
BOOL controlToggle;
|
||||
UINT32 KeyboardLayout;
|
||||
BOOL KeyboardState[256];
|
||||
@ -232,7 +232,7 @@ struct xf_context
|
||||
BOOL xrenderAvailable;
|
||||
|
||||
/* value to be sent over wire for each logical client mouse button */
|
||||
int button_map[NUM_BUTTONS_MAPPED];
|
||||
button_map button_map[NUM_BUTTONS_MAPPED];
|
||||
BYTE savedMaximizedState;
|
||||
};
|
||||
|
||||
|
||||
@ -303,24 +303,38 @@ out:
|
||||
}
|
||||
|
||||
int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
|
||||
const char* filename)
|
||||
int argc, char* argv[])
|
||||
{
|
||||
int status;
|
||||
int status, x;
|
||||
int ret = -1;
|
||||
char* filename;
|
||||
char* password = NULL;
|
||||
rdpAssistanceFile* file;
|
||||
|
||||
if (!settings || !argv || (argc < 2))
|
||||
return -1;
|
||||
|
||||
filename = argv[1];
|
||||
|
||||
for (x = 2; x < argc; x++)
|
||||
{
|
||||
const char* key = strstr(argv[x], "assistance:");
|
||||
|
||||
if (key)
|
||||
password = strchr(key, ':') + 1;
|
||||
}
|
||||
|
||||
file = freerdp_assistance_file_new();
|
||||
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
status = freerdp_assistance_parse_file(file, filename);
|
||||
status = freerdp_assistance_parse_file(file, filename, password);
|
||||
|
||||
if (status < 0)
|
||||
goto out;
|
||||
|
||||
status = freerdp_client_populate_settings_from_assistance_file(file, settings);
|
||||
|
||||
if (status < 0)
|
||||
if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
@ -492,6 +506,7 @@ static DWORD client_cli_accept_certificate(rdpSettings* settings)
|
||||
* when the connection requires it.
|
||||
* This function will actually be called by tls_verify_certificate().
|
||||
* @see rdp_client_connect() and tls_connect()
|
||||
* @deprecated Use client_cli_verify_certificate_ex
|
||||
* @param instance - pointer to the rdp_freerdp structure that contains the connection settings
|
||||
* @param common_name
|
||||
* @param subject
|
||||
@ -504,6 +519,7 @@ DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name,
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint, BOOL host_mismatch)
|
||||
{
|
||||
printf("WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
|
||||
printf("Certificate details:\n");
|
||||
printf("\tSubject: %s\n", subject);
|
||||
printf("\tIssuer: %s\n", issuer);
|
||||
@ -514,10 +530,50 @@ DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name,
|
||||
return client_cli_accept_certificate(instance->settings);
|
||||
}
|
||||
|
||||
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
|
||||
* when the connection requires it.
|
||||
* This function will actually be called by tls_verify_certificate().
|
||||
* @see rdp_client_connect() and tls_connect()
|
||||
* @param instance pointer to the rdp_freerdp structure that contains the connection settings
|
||||
* @param host The host currently connecting to
|
||||
* @param port The port currently connecting to
|
||||
* @param common_name The common name of the certificate, should match host or an alias of it
|
||||
* @param subject The subject of the certificate
|
||||
* @param issuer The certificate issuer name
|
||||
* @param fingerprint The fingerprint of the certificate
|
||||
* @param flags See VERIFY_CERT_FLAG_* for possible values.
|
||||
*
|
||||
* @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
|
||||
*/
|
||||
DWORD client_cli_verify_certificate_ex(freerdp* instance, const char* host, UINT16 port,
|
||||
const char* common_name,
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint, DWORD flags)
|
||||
{
|
||||
const char* type = "RDP-Server";
|
||||
|
||||
if (flags & VERIFY_CERT_FLAG_GATEWAY)
|
||||
type = "RDP-Gateway";
|
||||
|
||||
if (flags & VERIFY_CERT_FLAG_REDIRECT)
|
||||
type = "RDP-Redirect";
|
||||
|
||||
printf("Certificate details for %s:%"PRIu16" (%s):\n", host, port, type);
|
||||
printf("\tCommon Name: %s\n", common_name);
|
||||
printf("\tSubject: %s\n", subject);
|
||||
printf("\tIssuer: %s\n", issuer);
|
||||
printf("\tThumbprint: %s\n", fingerprint);
|
||||
printf("The above X.509 certificate could not be verified, possibly because you do not have\n"
|
||||
"the CA certificate in your certificate store, or the certificate has expired.\n"
|
||||
"Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
|
||||
return client_cli_accept_certificate(instance->settings);
|
||||
}
|
||||
|
||||
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
|
||||
* when a stored certificate does not match the remote counterpart.
|
||||
* This function will actually be called by tls_verify_certificate().
|
||||
* @see rdp_client_connect() and tls_connect()
|
||||
* @deprecated Use client_cli_verify_changed_certificate_ex
|
||||
* @param instance - pointer to the rdp_freerdp structure that contains the connection settings
|
||||
* @param common_name
|
||||
* @param subject
|
||||
@ -535,6 +591,7 @@ DWORD client_cli_verify_changed_certificate(freerdp* instance,
|
||||
const char* old_subject, const char* old_issuer,
|
||||
const char* old_fingerprint)
|
||||
{
|
||||
printf("WARNING: This callback is deprecated, migrate to client_cli_verify_changed_certificate_ex\n");
|
||||
printf("!!! Certificate has changed !!!\n");
|
||||
printf("\n");
|
||||
printf("New Certificate details:\n");
|
||||
@ -553,6 +610,59 @@ DWORD client_cli_verify_changed_certificate(freerdp* instance,
|
||||
return client_cli_accept_certificate(instance->settings);
|
||||
}
|
||||
|
||||
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
|
||||
* when a stored certificate does not match the remote counterpart.
|
||||
* This function will actually be called by tls_verify_certificate().
|
||||
* @see rdp_client_connect() and tls_connect()
|
||||
* @param instance pointer to the rdp_freerdp structure that contains the connection settings
|
||||
* @param host The host currently connecting to
|
||||
* @param port The port currently connecting to
|
||||
* @param common_name The common name of the certificate, should match host or an alias of it
|
||||
* @param subject The subject of the certificate
|
||||
* @param issuer The certificate issuer name
|
||||
* @param fingerprint The fingerprint of the certificate
|
||||
* @param old_subject The subject of the previous certificate
|
||||
* @param old_issuer The previous certificate issuer name
|
||||
* @param old_fingerprint The fingerprint of the previous certificate
|
||||
* @param flags See VERIFY_CERT_FLAG_* for possible values.
|
||||
*
|
||||
* @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
|
||||
*/
|
||||
DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
|
||||
const char* host, UINT16 port,
|
||||
const char* common_name,
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint,
|
||||
const char* old_subject, const char* old_issuer,
|
||||
const char* old_fingerprint, DWORD flags)
|
||||
{
|
||||
const char* type = "RDP-Server";
|
||||
|
||||
if (flags & VERIFY_CERT_FLAG_GATEWAY)
|
||||
type = "RDP-Gateway";
|
||||
|
||||
if (flags & VERIFY_CERT_FLAG_REDIRECT)
|
||||
type = "RDP-Redirect";
|
||||
|
||||
printf("!!!Certificate for %s:%"PRIu16" (%s) has changed!!!\n", host, port, type);
|
||||
printf("\n");
|
||||
printf("New Certificate details:\n");
|
||||
printf("\tCommon Name: %s\n", common_name);
|
||||
printf("\tSubject: %s\n", subject);
|
||||
printf("\tIssuer: %s\n", issuer);
|
||||
printf("\tThumbprint: %s\n", fingerprint);
|
||||
printf("\n");
|
||||
printf("Old Certificate details:\n");
|
||||
printf("\tSubject: %s\n", old_subject);
|
||||
printf("\tIssuer: %s\n", old_issuer);
|
||||
printf("\tThumbprint: %s\n", old_fingerprint);
|
||||
printf("\n");
|
||||
printf("The above X.509 certificate does not match the certificate used for previous connections.\n"
|
||||
"This may indicate that the certificate has been tampered with.\n"
|
||||
"Please contact the administrator of the RDP server and clarify.\n");
|
||||
return client_cli_accept_certificate(instance->settings);
|
||||
}
|
||||
|
||||
BOOL client_auto_reconnect(freerdp* instance)
|
||||
{
|
||||
return client_auto_reconnect_ex(instance, NULL);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -46,19 +46,20 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "bitmap-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "bitmap cache" },
|
||||
{ "bpp", COMMAND_LINE_VALUE_REQUIRED, "<depth>", "16", NULL, -1, NULL, "Session bpp (color depth)" },
|
||||
{ "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, NULL, NULL, NULL, -1, NULL, "Print the build configuration" },
|
||||
{ "cert-deny", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Automatically abort connection for any certificate that can not be validated." },
|
||||
{ "cert-ignore", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Ignore certificate" },
|
||||
{ "cert-name", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL, "Certificate name" },
|
||||
{ "cert-tofu", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Automatically accept certificate on first connect" },
|
||||
{ "client-hostname", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL, "Client Hostname to send to server" },
|
||||
{ "clipboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Redirect clipboard" },
|
||||
{ "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "rfx|nsc|jpeg", NULL, NULL, -1, NULL, "Bitmap codec cache" },
|
||||
{ "codec-cache", COMMAND_LINE_VALUE_REQUIRED, "[rfx|nsc|jpeg]", NULL, NULL, -1, NULL, "Bitmap codec cache" },
|
||||
{ "compression", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, "z", "compression" },
|
||||
{ "compression-level", COMMAND_LINE_VALUE_REQUIRED, "<level>", NULL, NULL, -1, NULL, "Compression level (0,1,2)" },
|
||||
{ "credentials-delegation", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "credentials delegation" },
|
||||
{ "d", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Domain" },
|
||||
{ "decorations", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Window decorations" },
|
||||
{ "disp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Display control" },
|
||||
{ "drive", COMMAND_LINE_VALUE_REQUIRED, "<name>,<path>", NULL, NULL, -1, NULL, "Redirect directory <path> as named share <name>" },
|
||||
{ "drive", COMMAND_LINE_VALUE_REQUIRED, "<name>,<path>", NULL, NULL, -1, NULL, "Redirect directory <path> as named share <name>. Hotplug support is enabled with /drive:hotplug,*. This argument provides the same function as \"Drives that I plug in later\" option in MSTSC." },
|
||||
{ "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect all mount points as shares" },
|
||||
{ "dvc", COMMAND_LINE_VALUE_REQUIRED, "<channel>[,<options>]", NULL, NULL, -1, NULL, "Dynamic virtual channel" },
|
||||
{ "dynamic-resolution", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Send resolution updates when the window is resized" },
|
||||
@ -68,19 +69,19 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "f", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Fullscreen mode (<Ctrl>+<Alt>+<Enter> toggles fullscreen)" },
|
||||
{ "fast-path", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "fast-path input/output" },
|
||||
{ "fipsmode", COMMAND_LINE_VALUE_BOOL, NULL, NULL, NULL, -1, NULL, "FIPS mode" },
|
||||
{ "floatbar", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "floatbar in fullscreen mode" },
|
||||
{ "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "smooth fonts (ClearType)" },
|
||||
{ "floatbar", COMMAND_LINE_VALUE_OPTIONAL, "sticky:[on|off],default:[visible|hidden],show:[always|fullscreen||window]", NULL, NULL, -1, NULL, "floatbar is disabled by default (when enabled defaults to sticky in fullscreen mode)" },
|
||||
{ "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "smooth fonts (ClearType)" },
|
||||
{ "frame-ack", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, "Number of frame acknowledgement" },
|
||||
{ "from-stdin", COMMAND_LINE_VALUE_OPTIONAL, "force", NULL, NULL, -1, NULL, "Read credentials from stdin. With <force> the prompt is done before connection, otherwise on server request." },
|
||||
{ "g", COMMAND_LINE_VALUE_REQUIRED, "<gateway>[:<port>]", NULL, NULL, -1, NULL, "Gateway Hostname" },
|
||||
{ "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "direct|detect", NULL, NULL, -1, "gum", "Gateway usage method" },
|
||||
{ "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "[direct|detect]", NULL, NULL, -1, "gum", "Gateway usage method" },
|
||||
{ "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" },
|
||||
{ "gdi", COMMAND_LINE_VALUE_REQUIRED, "sw|hw", NULL, NULL, -1, NULL, "GDI rendering" },
|
||||
{ "geometry", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Geometry tracking channel" },
|
||||
{ "gestures", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Consume multitouch input locally" },
|
||||
#ifdef WITH_GFX_H264
|
||||
{ "gfx", COMMAND_LINE_VALUE_OPTIONAL, "RFX|AVC420|AVC444", NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" },
|
||||
{ "gfx-h264", COMMAND_LINE_VALUE_OPTIONAL, "AVC420|AVC444", NULL, NULL, -1, NULL, "RDP8.1 graphics pipeline using H264 codec" },
|
||||
{ "gfx", COMMAND_LINE_VALUE_OPTIONAL, "[RFX|AVC420|AVC444]", NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" },
|
||||
{ "gfx-h264", COMMAND_LINE_VALUE_OPTIONAL, "[AVC420|AVC444]", NULL, NULL, -1, NULL, "RDP8.1 graphics pipeline using H264 codec" },
|
||||
#else
|
||||
{ "gfx", COMMAND_LINE_VALUE_OPTIONAL, "RFX", NULL, NULL, -1, NULL, "RDP8 graphics pipeline (experimental)" },
|
||||
#endif
|
||||
@ -90,8 +91,8 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "glyph-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Glyph cache (experimental)" },
|
||||
{ "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Gateway password" },
|
||||
{ "grab-keyboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Grab keyboard" },
|
||||
{ "gt", COMMAND_LINE_VALUE_REQUIRED, "rpc|http|auto", NULL, NULL, -1, NULL, "Gateway transport type" },
|
||||
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" },
|
||||
{ "gt", COMMAND_LINE_VALUE_REQUIRED, "[rpc|http|auto]", NULL, NULL, -1, NULL, "Gateway transport type" },
|
||||
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[[<domain>\\]<user>|<user>[@<domain>]]", NULL, NULL, -1, NULL, "Gateway username" },
|
||||
{ "gat", COMMAND_LINE_VALUE_REQUIRED, "<access token>", NULL, NULL, -1, NULL, "Gateway Access Token" },
|
||||
{ "h", COMMAND_LINE_VALUE_REQUIRED, "<height>", "768", NULL, -1, NULL, "Height" },
|
||||
{ "heartbeat", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support heartbeat PDUs" },
|
||||
@ -109,7 +110,7 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "kbd-type", COMMAND_LINE_VALUE_REQUIRED, "<id>", NULL, NULL, -1, NULL, "Keyboard type" },
|
||||
{ "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "<info-string>", NULL, NULL, -1, NULL, "Load balance info" },
|
||||
{ "log-filters", COMMAND_LINE_VALUE_REQUIRED, "<tag>:<level>[,<tag>:<level>[,...]]", NULL, NULL, -1, NULL, "Set logger filters, see wLog(7) for details" },
|
||||
{ "log-level", COMMAND_LINE_VALUE_REQUIRED, "OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE", NULL, NULL, -1, NULL, "Set the default log level, see wLog(7) for details" },
|
||||
{ "log-level", COMMAND_LINE_VALUE_REQUIRED, "[OFF|FATAL|ERROR|WARN|INFO|DEBUG|TRACE]", NULL, NULL, -1, NULL, "Set the default log level, see wLog(7) for details" },
|
||||
{ "max-fast-path-size", COMMAND_LINE_VALUE_REQUIRED, "<size>", NULL, NULL, -1, NULL, "Specify maximum fast-path update size" },
|
||||
{ "max-loop-time", COMMAND_LINE_VALUE_REQUIRED, "<time>", NULL, NULL, -1, NULL, "Specify maximum time in milliseconds spend treating packets"},
|
||||
{ "menu-anims", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "menu animations" },
|
||||
@ -122,10 +123,10 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "multitouch", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect multitouch input" },
|
||||
{ "multitransport", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Support multitransport protocol" },
|
||||
{ "nego", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "protocol security negotiation" },
|
||||
{ "network", COMMAND_LINE_VALUE_REQUIRED, "modem|broadband|broadband-low|broadband-high|wan|lan|auto", NULL, NULL, -1, NULL, "Network connection type" },
|
||||
{ "network", COMMAND_LINE_VALUE_REQUIRED, "[modem|broadband|broadband-low|broadband-high|wan|lan|auto]", NULL, NULL, -1, NULL, "Network connection type" },
|
||||
{ "nsc", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "nscodec", "NSCodec support" },
|
||||
{ "offscreen-cache", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "offscreen bitmap cache" },
|
||||
{ "orientation", COMMAND_LINE_VALUE_REQUIRED, "0|90|180|270", NULL, NULL, -1, NULL, "Orientation of display in degrees" },
|
||||
{ "orientation", COMMAND_LINE_VALUE_REQUIRED, "[0|90|180|270]", NULL, NULL, -1, NULL, "Orientation of display in degrees" },
|
||||
{ "old-license", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Use the old license workflow (no CAL and hwId set to 0)"},
|
||||
{ "p", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Password" },
|
||||
{ "parallel", COMMAND_LINE_VALUE_OPTIONAL, "<name>[,<path>]", NULL, NULL, -1, NULL, "Redirect parallel device" },
|
||||
@ -136,21 +137,25 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "pheight", COMMAND_LINE_VALUE_REQUIRED, "<height>", NULL, NULL, -1, NULL, "Physical height of display (in millimeters)" },
|
||||
{ "play-rfx", COMMAND_LINE_VALUE_REQUIRED, "<pcap-file>", NULL, NULL, -1, NULL, "Replay rfx pcap file" },
|
||||
{ "port", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, "Server port" },
|
||||
{ "suppress-output", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "suppress output when minimized" },
|
||||
{ "print-reconnect-cookie", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Print base64 reconnect cookie after connecting" },
|
||||
{ "printer", COMMAND_LINE_VALUE_OPTIONAL, "<name>[,<driver>]", NULL, NULL, -1, NULL, "Redirect printer device" },
|
||||
{ "proxy", COMMAND_LINE_VALUE_REQUIRED, "[<proto>://][<user>:<password>@]<host>:<port>", NULL, NULL, -1, NULL, "Proxy settings: override env.var (see also environment variable below).\n\tProtocol \"socks5\" should be given explicitly where \"http\" is default.\n\tNote: socks proxy is not supported by env. variable" },
|
||||
{
|
||||
"proxy", COMMAND_LINE_VALUE_REQUIRED, "[<proto>://][<user>:<password>@]<host>:<port>", NULL, NULL, -1, NULL,
|
||||
"Proxy settings: override env.var (see also environment variable below). Protocol \"socks5\" should be given explicitly where \"http\" is default. Note: socks proxy is not supported by env. variable"
|
||||
},
|
||||
{ "pth", COMMAND_LINE_VALUE_REQUIRED, "<password-hash>", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" },
|
||||
{ "pwidth", COMMAND_LINE_VALUE_REQUIRED, "<width>", NULL, NULL, -1, NULL, "Physical width of display (in millimeters)" },
|
||||
{ "reconnect-cookie", COMMAND_LINE_VALUE_REQUIRED, "<base64-cookie>", NULL, NULL, -1, NULL, "Pass base64 reconnect cookie to the connection" },
|
||||
{ "redirect-prefer", COMMAND_LINE_VALUE_REQUIRED, "<FQDN|IP|NETBIOS>[,<FQDN|IP|NETBIOS>[,<FQDN|IP|NETBIOS>]]", NULL, NULL, -1, NULL, "Override the preferred redirection order" },
|
||||
{ "redirect-prefer", COMMAND_LINE_VALUE_REQUIRED, "<FQDN|IP|NETBIOS>,[...]", NULL, NULL, -1, NULL, "Override the preferred redirection order" },
|
||||
{ "relax-order-checks", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "relax-order-checks", "Do not check if a RDP order was announced during capability exchange, only use when connecting to a buggy server" },
|
||||
{ "restricted-admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "restrictedAdmin", "Restricted admin mode" },
|
||||
{ "rfx", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "RemoteFX" },
|
||||
{ "rfx-mode", COMMAND_LINE_VALUE_REQUIRED, "image|video", NULL, NULL, -1, NULL, "RemoteFX mode" },
|
||||
{ "scale", COMMAND_LINE_VALUE_REQUIRED, "100|140|180", "100", NULL, -1, NULL, "Scaling factor of the display" },
|
||||
{ "rfx-mode", COMMAND_LINE_VALUE_REQUIRED, "[image|video]", NULL, NULL, -1, NULL, "RemoteFX mode" },
|
||||
{ "scale", COMMAND_LINE_VALUE_REQUIRED, "[100|140|180]", "100", NULL, -1, NULL, "Scaling factor of the display" },
|
||||
{ "scale-desktop", COMMAND_LINE_VALUE_REQUIRED, "<percentage>", "100", NULL, -1, NULL, "Scaling factor for desktop applications (value between 100 and 500)" },
|
||||
{ "scale-device", COMMAND_LINE_VALUE_REQUIRED, "100|140|180", "100", NULL, -1, NULL, "Scaling factor for app store applications" },
|
||||
{ "sec", COMMAND_LINE_VALUE_REQUIRED, "rdp|tls|nla|ext", NULL, NULL, -1, NULL, "Force specific protocol security" },
|
||||
{ "sec", COMMAND_LINE_VALUE_REQUIRED, "[rdp|tls|nla|ext]", NULL, NULL, -1, NULL, "Force specific protocol security" },
|
||||
{ "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "NLA extended protocol security" },
|
||||
{ "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "NLA protocol security" },
|
||||
{ "sec-rdp", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "RDP protocol security" },
|
||||
@ -160,7 +165,7 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "shell-dir", COMMAND_LINE_VALUE_REQUIRED, "<dir>", NULL, NULL, -1, NULL, "Shell working directory" },
|
||||
{ "size", COMMAND_LINE_VALUE_REQUIRED, "<width>x<height> or <percent>%[wh]", "1024x768", NULL, -1, NULL, "Screen size" },
|
||||
{ "smart-sizing", COMMAND_LINE_VALUE_OPTIONAL, "<width>x<height>", NULL, NULL, -1, NULL, "Scale remote desktop to window size" },
|
||||
{ "smartcard", COMMAND_LINE_VALUE_OPTIONAL, "<str>[,<str>…]", NULL, NULL, -1, NULL, "Redirect the smartcard devices containing any of the <str> in their names." },
|
||||
{ "smartcard", COMMAND_LINE_VALUE_OPTIONAL, "<str>[,<str>...]", NULL, NULL, -1, NULL, "Redirect the smartcard devices containing any of the <str> in their names." },
|
||||
{ "smartcard-logon", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Activates Smartcard Logon authentication. (EXPERIMENTAL: NLA not supported)" },
|
||||
{ "sound", COMMAND_LINE_VALUE_OPTIONAL, "[sys:<sys>,][dev:<dev>,][format:<format>,][rate:<rate>,][channel:<channel>,][latency:<latency>,][quality:<quality>]", NULL, NULL, -1, "audio", "Audio output (sound)" },
|
||||
{ "span", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Span screen over multiple monitors" },
|
||||
@ -168,10 +173,10 @@ static COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "ssh-agent", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "ssh-agent", "SSH Agent forwarding channel" },
|
||||
{ "t", COMMAND_LINE_VALUE_REQUIRED, "<title>", NULL, NULL, -1, "title", "Window title" },
|
||||
{ "themes", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "themes" },
|
||||
{ "tls-ciphers", COMMAND_LINE_VALUE_REQUIRED, "netmon|ma|ciphers", NULL, NULL, -1, NULL, "Allowed TLS ciphers" },
|
||||
{ "tls-ciphers", COMMAND_LINE_VALUE_REQUIRED, "[netmon|ma|ciphers]", NULL, NULL, -1, NULL, "Allowed TLS ciphers" },
|
||||
{ "tls-seclevel", COMMAND_LINE_VALUE_REQUIRED, "<level>", "1", NULL, -1, NULL, "TLS security level - defaults to 1" },
|
||||
{ "toggle-fullscreen", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Alt+Ctrl+Enter toggles fullscreen" },
|
||||
{ "u", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Username" },
|
||||
{ "toggle-fullscreen", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Alt+Ctrl+Enter to toggle fullscreen" },
|
||||
{ "u", COMMAND_LINE_VALUE_REQUIRED, "[[<domain>\\]<user>|<user>[@<domain>]]", NULL, NULL, -1, NULL, "Username" },
|
||||
{ "unmap-buttons", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Let server see real physical pointer button"},
|
||||
{ "usb", COMMAND_LINE_VALUE_REQUIRED, "[dbg,][dev:<dev>,][id|addr,][auto]", NULL, NULL, -1, NULL, "Redirect USB device" },
|
||||
{ "v", COMMAND_LINE_VALUE_REQUIRED, "<server>[:port]", NULL, NULL, -1, NULL, "Server hostname" },
|
||||
|
||||
@ -649,9 +649,9 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe
|
||||
}
|
||||
CommandLineSwitchCase(arg, "x")
|
||||
{
|
||||
long type;
|
||||
unsigned long type;
|
||||
char* pEnd;
|
||||
type = strtol(arg->Value, &pEnd, 16);
|
||||
type = strtoul(arg->Value, &pEnd, 16);
|
||||
|
||||
if (errno != 0)
|
||||
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
|
||||
|
||||
@ -1133,9 +1133,6 @@ if( APPLE )
|
||||
mark_as_advanced( CMAKE_INSTALL_NAME_TOOL )
|
||||
endif()
|
||||
|
||||
# Force set compilers because standard identification works badly for us
|
||||
include( CMakeForceCompiler )
|
||||
CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
|
||||
if( ANDROID_COMPILER_IS_CLANG )
|
||||
set( CMAKE_C_COMPILER_ID Clang )
|
||||
endif()
|
||||
@ -1147,7 +1144,6 @@ else()
|
||||
endif()
|
||||
set( CMAKE_C_HAS_ISYSROOT 1 )
|
||||
set( CMAKE_C_COMPILER_ABI ELF )
|
||||
CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU )
|
||||
if( ANDROID_COMPILER_IS_CLANG )
|
||||
set( CMAKE_CXX_COMPILER_ID Clang)
|
||||
endif()
|
||||
|
||||
@ -136,6 +136,7 @@ option(WITH_DEBUG_RINGBUFFER "Enable Ringbuffer debug messages" ${DEFAULT_DEBUG_
|
||||
option(WITH_DEBUG_SYMBOLS "Pack debug symbols to installer" OFF)
|
||||
option(WITH_CCACHE "Use ccache support if available" ON)
|
||||
option(WITH_ICU "Use ICU for unicode conversion" OFF)
|
||||
option(WITH_GSSAPI "Compile support for kerberos authentication. (EXPERIMENTAL)" OFF)
|
||||
|
||||
option(WITH_DSP_EXPERIMENTAL "Enable experimental sound encoder/decoder formats" OFF)
|
||||
if (WITH_FFMPEG)
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
# - Find DirectFB
|
||||
# Find the DirectFB libraries
|
||||
#
|
||||
# This module defines the following variables:
|
||||
# DIRECTFB_FOUND - true if DIRECTFB_INCLUDE_DIR & DIRECTFB_LIBRARY are found
|
||||
# DIRECTFB_LIBRARIES - Set when DIRECTFB_LIBRARY is found
|
||||
# DIRECTFB_INCLUDE_DIRS - Set when DIRECTFB_INCLUDE_DIR is found
|
||||
#
|
||||
# DIRECTFB_INCLUDE_DIR - where to find CUnit.h, etc.
|
||||
# DIRECTFB_LIBRARY - the cunit library
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 O.S. Systems Software Ltda.
|
||||
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
|
||||
# Copyright 2011 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.
|
||||
#=============================================================================
|
||||
|
||||
find_path(DIRECTFB_INCLUDE_DIR NAMES directfb.h
|
||||
PATH_SUFFIXES directfb
|
||||
DOC "The directfb include directory"
|
||||
)
|
||||
|
||||
find_library(DIRECTFB_LIBRARY NAMES directfb
|
||||
DOC "The DirectFB library"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DirectFB DEFAULT_MSG DIRECTFB_LIBRARY DIRECTFB_INCLUDE_DIR)
|
||||
|
||||
if(DIRECTFB_FOUND)
|
||||
set( DIRECTFB_LIBRARIES ${DIRECTFB_LIBRARY} )
|
||||
set( DIRECTFB_INCLUDE_DIRS ${DIRECTFB_INCLUDE_DIR} )
|
||||
endif()
|
||||
|
||||
mark_as_advanced(DIRECTFB_INCLUDE_DIR DIRECTFB_LIBRARY)
|
||||
|
||||
@ -115,7 +115,7 @@ if(NOT GSS_FOUND) # not found by pkg-config. Let's take more traditional approac
|
||||
string(STRIP "${_GSS_VENDOR}" _GSS_VENDOR)
|
||||
if((GSS_FLAVOUR STREQUAL "Heimdal" AND NOT _GSS_VENDOR STREQUAL "Heimdal")
|
||||
OR (GSS_FLAVOUR STREQUAL "MIT" AND NOT _GSS_VENDOR STREQUAL "Massachusetts Institute of Technology"))
|
||||
message(SEND_ERROR "GSS vendor and GSS flavour are not matching : _GSS_VENDOR=${_GSS_VENDOR} ; GSS_FLAVOUR=${GSS_FLAVOUR}")
|
||||
message(SEND_ERROR "GSS vendor and GSS flavour are not matching : _GSS_VENDOR=${_GSS_VENDOR} ; GSS_FLAVOUR=${GSS_FLAVOUR}")
|
||||
message(STATUS "Try to set the path to GSS root folder in the system variable GSS_ROOT_DIR")
|
||||
endif()
|
||||
else()
|
||||
@ -428,13 +428,17 @@ if(GSS_FLAVOUR STREQUAL "MIT")
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MAJOR "${GSS_VERSION_MAJOR}")
|
||||
string(REGEX MATCH "\\.([0-9]+)$" GSS_VERSION_MINOR ${GSS_RELEASE_NUMBER})
|
||||
if(NOT GSS_VERSION_MINOR)
|
||||
string(REGEX MATCH "\\.([0-9]+)\\." GSS_VERSION_MINOR ${GSS_RELEASE_NUMBER})
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
string(REGEX MATCH "([0-9]+)$" GSS_VERSION_PATCH ${GSS_RELEASE_NUMBER})
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_PATCH "${GSS_VERSION_PATCH}")
|
||||
string(REGEX MATCH "\\.([0-9]+)[-\\.]" GSS_VERSION_MINOR ${GSS_RELEASE_NUMBER})
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
string(REGEX REPLACE "-" "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
string(REGEX MATCH "\\.([0-9]+)$" GSS_VERSION_PATCH "${GSS_RELEASE_NUMBER}")
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_PATCH "${GSS_VERSION_PATCH}")
|
||||
if(NOT GSS_VERSION_PATCH)
|
||||
set(GSS_VERSION_PATCH "0")
|
||||
endif()
|
||||
else()
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
string(REGEX REPLACE "\\." "" GSS_VERSION_MINOR "${GSS_VERSION_MINOR}")
|
||||
set(GSS_VERSION_PATCH "0")
|
||||
endif()
|
||||
if(GSS_VERSION_MAJOR AND GSS_VERSION_MINOR)
|
||||
@ -443,6 +447,7 @@ if(GSS_FLAVOUR STREQUAL "MIT")
|
||||
else()
|
||||
message(SEND_ERROR "Failed to retrieved Kerberos version number")
|
||||
endif()
|
||||
message(STATUS "Located Kerberos ${GSS_VERSION_MAJOR}.${GSS_VERSION_MINOR}.${GSS_VERSION_PATCH}")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)
|
||||
|
||||
@ -63,13 +63,13 @@ FIND_PATH(OPENSSL_INCLUDE_DIR
|
||||
include
|
||||
)
|
||||
|
||||
IF(WIN32)
|
||||
IF(MSVC)
|
||||
if(${MSVC_RUNTIME} STREQUAL "static")
|
||||
set(MSVC_RUNTIME_SUFFIX "MT")
|
||||
else()
|
||||
set(MSVC_RUNTIME_SUFFIX "MD")
|
||||
endif()
|
||||
ENDIF(WIN32)
|
||||
ENDIF(MSVC)
|
||||
|
||||
IF(ANDROID)
|
||||
FIND_LIBRARY(OPENSSL_LIBRARIES
|
||||
@ -108,6 +108,7 @@ ELSEIF(WIN32 AND NOT CYGWIN)
|
||||
"libeay32${MSVC_RUNTIME_SUFFIX}d"
|
||||
libeay32
|
||||
libcrypto
|
||||
libcrypto-1_1
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
${MSVC_RUNTIME_PATH_SUFFIX}
|
||||
@ -121,6 +122,7 @@ ELSEIF(WIN32 AND NOT CYGWIN)
|
||||
"libeay32${MSVC_RUNTIME_SUFFIX}"
|
||||
libeay32
|
||||
libcrypto
|
||||
libcrypto-1_1
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
${MSVC_RUNTIME_PATH_SUFFIX}
|
||||
@ -135,6 +137,7 @@ ELSEIF(WIN32 AND NOT CYGWIN)
|
||||
ssleay32
|
||||
ssl
|
||||
libssl
|
||||
libssl-1_1
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
${MSVC_RUNTIME_PATH_SUFFIX}
|
||||
@ -149,6 +152,7 @@ ELSEIF(WIN32 AND NOT CYGWIN)
|
||||
ssleay32
|
||||
ssl
|
||||
libssl
|
||||
libssl-1_1
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
${MSVC_RUNTIME_PATH_SUFFIX}
|
||||
@ -193,6 +197,7 @@ ELSEIF(WIN32 AND NOT CYGWIN)
|
||||
NAMES
|
||||
libeay32
|
||||
libcrypto
|
||||
libcrypto-1_1
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
@ -204,6 +209,7 @@ ELSEIF(WIN32 AND NOT CYGWIN)
|
||||
NAMES
|
||||
ssleay32
|
||||
libssl
|
||||
libssl-1_1
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
@ -220,6 +226,7 @@ ELSE(WIN32 AND NOT CYGWIN)
|
||||
NAMES
|
||||
ssl
|
||||
ssleay32
|
||||
libssl-1_1
|
||||
"ssleay32${MSVC_RUNTIME_SUFFIX}"
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
@ -231,6 +238,7 @@ ELSE(WIN32 AND NOT CYGWIN)
|
||||
FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARY
|
||||
NAMES
|
||||
crypto
|
||||
libcrypto-1_1
|
||||
HINTS
|
||||
${_OPENSSL_LIBDIR}
|
||||
${_OPENSSL_ROOT_HINTS_AND_PATHS}
|
||||
|
||||
@ -30,6 +30,7 @@ include(FindPkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(WAYLAND_SCANNER_PC wayland-scanner)
|
||||
pkg_check_modules(WAYLAND_CLIENT_PC wayland-client)
|
||||
pkg_check_modules(WAYLAND_CURSOR_PC wayland-cursor)
|
||||
pkg_check_modules(XKBCOMMON_PC xkbcommon)
|
||||
endif()
|
||||
|
||||
@ -41,11 +42,20 @@ find_path(WAYLAND_INCLUDE_DIR wayland-client.h
|
||||
HINTS ${WAYLAND_CLIENT_PC_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(WAYLAND_LIBS
|
||||
find_library(WAYLAND_CLIENT_LIB
|
||||
NAMES "wayland-client"
|
||||
HINTS "${WAYLAND_CLIENT_PC_LIBRARY_DIRS}"
|
||||
)
|
||||
|
||||
find_library(WAYLAND_CURSOR_LIB
|
||||
NAMES "wayland-cursor"
|
||||
HINTS "${WAYLAND_CURSOR_PC_LIBRARY_DIRS}"
|
||||
)
|
||||
|
||||
if (WAYLAND_CLIENT_LIB AND WAYLAND_CURSOR_LIB)
|
||||
list(APPEND WAYLAND_LIBS ${WAYLAND_CLIENT_LIB} ${WAYLAND_CURSOR_LIB})
|
||||
endif (WAYLAND_CLIENT_LIB AND WAYLAND_CURSOR_LIB)
|
||||
|
||||
find_path(XKBCOMMON_INCLUDE_DIR xkbcommon/xkbcommon.h
|
||||
HINTS ${XKBCOMMON_PC_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
@ -37,7 +37,7 @@ set (APPLE True)
|
||||
set (IOS True)
|
||||
|
||||
# Required as of cmake 2.8.10
|
||||
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||
#set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||
|
||||
# Determine the cmake host system version so we know where to find the iOS SDKs
|
||||
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
#cmakedefine WITH_SOXR
|
||||
#cmakedefine WITH_GFX_H264
|
||||
#cmakedefine WITH_OPENH264
|
||||
#cmakedefine WITH_OPENH264_LOADING
|
||||
#cmakedefine WITH_FFMPEG
|
||||
#cmakedefine WITH_DSP_EXPERIMENTAL
|
||||
#cmakedefine WITH_DSP_FFMPEG
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
The dfreerdp FreeRDP client is currently orphaned and unmaintained so please don't expect it to build and work without problems.
|
||||
|
||||
If you are interested to update and maintain the dfreerdp client please let us know.
|
||||
@ -23,63 +23,38 @@
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
struct rdp_assistance_file
|
||||
{
|
||||
UINT32 Type;
|
||||
|
||||
char* Username;
|
||||
char* LHTicket;
|
||||
char* RCTicket;
|
||||
char* PassStub;
|
||||
UINT32 DtStart;
|
||||
UINT32 DtLength;
|
||||
BOOL LowSpeed;
|
||||
BOOL RCTicketEncrypted;
|
||||
|
||||
char* ConnectionString1;
|
||||
char* ConnectionString2;
|
||||
|
||||
BYTE* EncryptedPassStub;
|
||||
int EncryptedPassStubLength;
|
||||
|
||||
BYTE* EncryptedLHTicket;
|
||||
int EncryptedLHTicketLength;
|
||||
|
||||
char* MachineAddress;
|
||||
UINT32 MachinePort;
|
||||
|
||||
UINT32 MachineCount;
|
||||
char** MachineAddresses;
|
||||
UINT32* MachinePorts;
|
||||
|
||||
char* RASessionId;
|
||||
char* RASpecificParams;
|
||||
};
|
||||
typedef struct rdp_assistance_file rdpAssistanceFile;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FREERDP_API BYTE* freerdp_assistance_hex_string_to_bin(const char* str, int* size);
|
||||
FREERDP_API char* freerdp_assistance_bin_to_hex_string(const BYTE* data, int size);
|
||||
|
||||
FREERDP_API int freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file);
|
||||
FREERDP_API int freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file);
|
||||
FREERDP_API BYTE* freerdp_assistance_hex_string_to_bin(const void* str, size_t* size);
|
||||
FREERDP_API char* freerdp_assistance_bin_to_hex_string(const void* data, size_t size);
|
||||
|
||||
FREERDP_API char* freerdp_assistance_generate_pass_stub(DWORD flags);
|
||||
FREERDP_API char* freerdp_assistance_construct_expert_blob(const char* name, const char* pass);
|
||||
FREERDP_API BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub, int* pEncryptedSize);
|
||||
FREERDP_API BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub,
|
||||
size_t* pEncryptedSize);
|
||||
|
||||
FREERDP_API int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer, size_t size);
|
||||
FREERDP_API int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name);
|
||||
FREERDP_API int freerdp_assistance_decrypt(rdpAssistanceFile* file, const char* password);
|
||||
FREERDP_API int freerdp_assistance_set_connection_string2(rdpAssistanceFile* file,
|
||||
const char* string, const char* password);
|
||||
|
||||
FREERDP_API int freerdp_client_populate_settings_from_assistance_file(rdpAssistanceFile* file, rdpSettings* settings);
|
||||
FREERDP_API int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* buffer,
|
||||
size_t size, const char* password);
|
||||
FREERDP_API int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name,
|
||||
const char* password);
|
||||
|
||||
FREERDP_API BOOL freerdp_assistance_populate_settings_from_assistance_file(rdpAssistanceFile* file,
|
||||
rdpSettings* settings);
|
||||
FREERDP_API BOOL freerdp_assistance_get_encrypted_pass_stub(rdpAssistanceFile* file,
|
||||
const char** pwd, size_t* size);
|
||||
|
||||
FREERDP_API rdpAssistanceFile* freerdp_assistance_file_new(void);
|
||||
FREERDP_API void freerdp_assistance_file_free(rdpAssistanceFile* file);
|
||||
|
||||
FREERDP_API void freerdp_assistance_print_file(rdpAssistanceFile* file, wLog* log, DWORD level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -203,7 +203,7 @@ struct _CLIPRDR_FORMAT_DATA_RESPONSE
|
||||
{
|
||||
DEFINE_CLIPRDR_HEADER_COMMON();
|
||||
|
||||
BYTE* requestedFormatData;
|
||||
const BYTE* requestedFormatData;
|
||||
};
|
||||
typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE;
|
||||
|
||||
@ -229,7 +229,7 @@ struct _CLIPRDR_FILE_CONTENTS_RESPONSE
|
||||
UINT32 streamId;
|
||||
UINT32 dwFlags;
|
||||
UINT32 cbRequested;
|
||||
BYTE* requestedData;
|
||||
const BYTE* requestedData;
|
||||
};
|
||||
typedef struct _CLIPRDR_FILE_CONTENTS_RESPONSE CLIPRDR_FILE_CONTENTS_RESPONSE;
|
||||
|
||||
|
||||
@ -316,6 +316,8 @@ typedef struct _DEVICE DEVICE;
|
||||
typedef struct _IRP IRP;
|
||||
typedef struct _DEVMAN DEVMAN;
|
||||
|
||||
typedef UINT(*pcCustomComponentRequest)(DEVICE* device, UINT16 component, UINT16 packetId,
|
||||
wStream* s);
|
||||
typedef UINT(*pcIRPRequest)(DEVICE* device, IRP* irp);
|
||||
typedef UINT(*pcInitDevice)(DEVICE* device);
|
||||
typedef UINT(*pcFreeDevice)(DEVICE* device);
|
||||
@ -328,6 +330,7 @@ struct _DEVICE
|
||||
const char* name;
|
||||
wStream* data;
|
||||
|
||||
pcCustomComponentRequest CustomComponentRequest;
|
||||
pcIRPRequest IRPRequest;
|
||||
pcInitDevice Init;
|
||||
pcFreeDevice Free;
|
||||
|
||||
@ -96,7 +96,7 @@ FREERDP_API int freerdp_client_settings_write_connection_file(const rdpSettings*
|
||||
const char* filename, BOOL unicode);
|
||||
|
||||
FREERDP_API int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
|
||||
const char* filename);
|
||||
int argc, char* argv[]);
|
||||
|
||||
FREERDP_API BOOL client_cli_authenticate(freerdp* instance, char** username, char** password,
|
||||
char** domain);
|
||||
@ -107,11 +107,25 @@ FREERDP_API DWORD client_cli_verify_certificate(freerdp* instance, const char* c
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint, BOOL host_mismatch);
|
||||
|
||||
FREERDP_API DWORD client_cli_verify_certificate_ex(freerdp* instance,
|
||||
const char* host, UINT16 port,
|
||||
const char* common_name,
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint, DWORD flags);
|
||||
|
||||
FREERDP_API DWORD client_cli_verify_changed_certificate(freerdp* instance, const char* common_name,
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint,
|
||||
const char* old_subject, const char* old_issuer,
|
||||
const char* old_fingerprint);
|
||||
|
||||
FREERDP_API DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
|
||||
const char* host, UINT16 port,
|
||||
const char* common_name,
|
||||
const char* subject, const char* issuer,
|
||||
const char* fingerprint,
|
||||
const char* old_subject, const char* old_issuer,
|
||||
const char* old_fingerprint, DWORD flags);
|
||||
FREERDP_API BOOL client_auto_reconnect(freerdp* instance);
|
||||
FREERDP_API BOOL client_auto_reconnect_ex(freerdp* instance,
|
||||
BOOL(*window_events)(freerdp* instance));
|
||||
|
||||
@ -34,26 +34,26 @@
|
||||
|
||||
typedef struct _cliprdr_client_context CliprdrClientContext;
|
||||
|
||||
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities);
|
||||
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext* context, CLIPRDR_CAPABILITIES* capabilities);
|
||||
typedef UINT (*pcCliprdrMonitorReady)(CliprdrClientContext* context, CLIPRDR_MONITOR_READY* monitorReady);
|
||||
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext* context, CLIPRDR_TEMP_DIRECTORY* tempDirectory);
|
||||
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList);
|
||||
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST* formatList);
|
||||
typedef UINT (*pcCliprdrClientFormatListResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatListResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
|
||||
typedef UINT (*pcCliprdrClientLockClipboardData)(CliprdrClientContext* context, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerLockClipboardData)(CliprdrClientContext* context, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientUnlockClipboardData)(CliprdrClientContext* context, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerUnlockClipboardData)(CliprdrClientContext* context, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientFormatDataRequest)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
|
||||
typedef UINT (*pcCliprdrServerFormatDataRequest)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
|
||||
typedef UINT (*pcCliprdrClientFormatDataResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatDataResponse)(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
|
||||
typedef UINT (*pcCliprdrClientFileContentsRequest)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrServerFileContentsRequest)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrClientFileContentsResponse)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse);
|
||||
typedef UINT (*pcCliprdrServerFileContentsResponse)(CliprdrClientContext* context, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse);
|
||||
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext* context, const CLIPRDR_CAPABILITIES* capabilities);
|
||||
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext* context, const CLIPRDR_CAPABILITIES* capabilities);
|
||||
typedef UINT (*pcCliprdrMonitorReady)(CliprdrClientContext* context, const CLIPRDR_MONITOR_READY* monitorReady);
|
||||
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext* context, const CLIPRDR_TEMP_DIRECTORY* tempDirectory);
|
||||
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext* context, const CLIPRDR_FORMAT_LIST* formatList);
|
||||
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext* context, const CLIPRDR_FORMAT_LIST* formatList);
|
||||
typedef UINT (*pcCliprdrClientFormatListResponse)(CliprdrClientContext* context, const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatListResponse)(CliprdrClientContext* context, const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
|
||||
typedef UINT (*pcCliprdrClientLockClipboardData)(CliprdrClientContext* context, const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerLockClipboardData)(CliprdrClientContext* context, const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientUnlockClipboardData)(CliprdrClientContext* context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrServerUnlockClipboardData)(CliprdrClientContext* context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData);
|
||||
typedef UINT (*pcCliprdrClientFormatDataRequest)(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
|
||||
typedef UINT (*pcCliprdrServerFormatDataRequest)(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
|
||||
typedef UINT (*pcCliprdrClientFormatDataResponse)(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
|
||||
typedef UINT (*pcCliprdrServerFormatDataResponse)(CliprdrClientContext* context, const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
|
||||
typedef UINT (*pcCliprdrClientFileContentsRequest)(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrServerFileContentsRequest)(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest);
|
||||
typedef UINT (*pcCliprdrClientFileContentsResponse)(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse);
|
||||
typedef UINT (*pcCliprdrServerFileContentsResponse)(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse);
|
||||
|
||||
struct _cliprdr_client_context
|
||||
{
|
||||
|
||||
@ -46,7 +46,7 @@ FREERDP_API BOOL freerdp_client_print_command_line_help_ex(
|
||||
|
||||
FREERDP_API BOOL freerdp_parse_username(const char* username, char** user, char** domain);
|
||||
FREERDP_API BOOL freerdp_parse_hostname(const char* hostname, char** host, int* port);
|
||||
FREERDP_API BOOL freerdp_set_connection_type(rdpSettings* settings, int type);
|
||||
FREERDP_API BOOL freerdp_set_connection_type(rdpSettings* settings, UINT32 type);
|
||||
|
||||
FREERDP_API BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, char** params);
|
||||
FREERDP_API BOOL freerdp_client_add_static_channel(rdpSettings* settings, int count, char** params);
|
||||
|
||||
@ -78,13 +78,14 @@ typedef void* (*pcRdpgfxGetCacheSlotData)(RdpgfxClientContext* context,
|
||||
typedef UINT(*pcRdpgfxUpdateSurfaces)(RdpgfxClientContext* context);
|
||||
|
||||
typedef UINT(*pcRdpgfxUpdateSurfaceArea)(RdpgfxClientContext* context, UINT16 surfaceId,
|
||||
UINT32 nrRects, const RECTANGLE_16* rects);
|
||||
UINT32 nrRects, const RECTANGLE_16* rects);
|
||||
|
||||
struct _rdpgfx_client_context
|
||||
{
|
||||
void* handle;
|
||||
void* custom;
|
||||
|
||||
/* Implementations require locking */
|
||||
pcRdpgfxResetGraphics ResetGraphics;
|
||||
pcRdpgfxStartFrame StartFrame;
|
||||
pcRdpgfxEndFrame EndFrame;
|
||||
@ -108,9 +109,11 @@ struct _rdpgfx_client_context
|
||||
pcRdpgfxSetCacheSlotData SetCacheSlotData;
|
||||
pcRdpgfxGetCacheSlotData GetCacheSlotData;
|
||||
|
||||
/* No locking required */
|
||||
pcRdpgfxUpdateSurfaces UpdateSurfaces;
|
||||
pcRdpgfxUpdateSurfaceArea UpdateSurfaceArea;
|
||||
|
||||
CRITICAL_SECTION mux;
|
||||
PROFILER_DEFINE(SurfaceProfiler)
|
||||
};
|
||||
|
||||
|
||||
@ -155,6 +155,8 @@ struct _RFX_CONTEXT
|
||||
|
||||
/* decoded header blocks */
|
||||
UINT32 decodedHeaderBlocks;
|
||||
UINT16 expectedDataBlockType;
|
||||
RFX_MESSAGE currentMessage;
|
||||
|
||||
/* routines */
|
||||
void (*quantization_decode)(INT16* buffer, const UINT32* quantization_values);
|
||||
|
||||
@ -51,35 +51,35 @@ struct rdp_certificate_store
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FREERDP_API rdpCertificateData* certificate_data_new(
|
||||
char* hostname, UINT16 port, char* subject,
|
||||
char* issuer, char* fingerprint);
|
||||
const char* hostname, UINT16 port, const char* subject,
|
||||
const char* issuer, const char* fingerprint);
|
||||
FREERDP_API void certificate_data_free(
|
||||
rdpCertificateData* certificate_data);
|
||||
rdpCertificateData* certificate_data);
|
||||
FREERDP_API rdpCertificateStore* certificate_store_new(
|
||||
rdpSettings* settings);
|
||||
rdpSettings* settings);
|
||||
FREERDP_API BOOL certificate_data_replace(
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
FREERDP_API void certificate_store_free(
|
||||
rdpCertificateStore* certificate_store);
|
||||
rdpCertificateStore* certificate_store);
|
||||
FREERDP_API int certificate_data_match(
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
FREERDP_API BOOL certificate_data_print(
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data);
|
||||
FREERDP_API BOOL certificate_get_stored_data(
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data,
|
||||
char** subject, char** issuer,
|
||||
char** fingerprint);
|
||||
rdpCertificateStore* certificate_store,
|
||||
rdpCertificateData* certificate_data,
|
||||
char** subject, char** issuer,
|
||||
char** fingerprint);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_CRYPTO_CERTIFICATE_H */
|
||||
|
||||
@ -72,10 +72,10 @@ Note: email and upn amongst others are also alt_names,
|
||||
but the old crypto_cert_get_alt_names returned only the dns_names
|
||||
*/
|
||||
FREERDP_API char** crypto_cert_subject_alt_name(X509* xcert, int* count, int** lengths);
|
||||
FREERDP_API void crypto_cert_subject_alt_name_free(int count, int *lengths, char** alt_names);
|
||||
FREERDP_API void crypto_cert_subject_alt_name_free(int count, int* lengths, char** alt_names);
|
||||
|
||||
FREERDP_API BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path);
|
||||
FREERDP_API rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname,
|
||||
FREERDP_API BOOL x509_verify_certificate(CryptoCert cert, const char* certificate_store_path);
|
||||
FREERDP_API rdpCertificateData* crypto_get_certificate_data(X509* xcert, const char* hostname,
|
||||
UINT16 port);
|
||||
FREERDP_API BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey,
|
||||
DWORD* PublicKeyLength);
|
||||
|
||||
@ -96,16 +96,6 @@ FREERDP_API int tls_write_all(rdpTls* tls, const BYTE* data, int length);
|
||||
|
||||
FREERDP_API int tls_set_alert_code(rdpTls* tls, int level, int description);
|
||||
|
||||
FREERDP_API BOOL tls_match_hostname(char* pattern, int pattern_length, char* hostname);
|
||||
FREERDP_API int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
|
||||
FREERDP_API void tls_print_certificate_error(char* hostname, UINT16 port,
|
||||
char* fingerprint, char* hosts_file);
|
||||
FREERDP_API void tls_print_certificate_name_mismatch_error(
|
||||
char* hostname, UINT16 port, char* common_name, char** alt_names,
|
||||
int alt_names_count);
|
||||
|
||||
FREERDP_API BOOL tls_print_error(char* func, SSL* connection, int value);
|
||||
|
||||
FREERDP_API rdpTls* tls_new(rdpSettings* settings);
|
||||
FREERDP_API void tls_free(rdpTls* tls);
|
||||
|
||||
|
||||
@ -45,19 +45,6 @@ extern "C" {
|
||||
#define ERRINFO_RPC_INITIATED_DISCONNECT_BY_USER 0x0000000B
|
||||
#define ERRINFO_LOGOFF_BY_USER 0x0000000C
|
||||
|
||||
/* Protocol-independent codes generated by the Connection Broker */
|
||||
#define ERRINFO_CB_DESTINATION_NOT_FOUND 0x0000400
|
||||
#define ERRINFO_CB_LOADING_DESTINATION 0x0000402
|
||||
#define ERRINFO_CB_REDIRECTING_TO_DESTINATION 0x0000404
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_WAKE 0x0000405
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT 0x0000406
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS 0x0000407
|
||||
#define ERRINFO_CB_DESTINATION_POOL_NOT_FREE 0x0000408
|
||||
#define ERRINFO_CB_CONNECTION_CANCELLED 0x0000409
|
||||
#define ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS 0x0000410
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT 0x0000411
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED 0x0000412
|
||||
|
||||
/* Protocol-independent licensing codes */
|
||||
#define ERRINFO_LICENSE_INTERNAL 0x00000100
|
||||
#define ERRINFO_LICENSE_NO_LICENSE_SERVER 0x00000101
|
||||
@ -71,6 +58,19 @@ extern "C" {
|
||||
#define ERRINFO_LICENSE_CANT_UPGRADE_LICENSE 0x00000109
|
||||
#define ERRINFO_LICENSE_NO_REMOTE_CONNECTIONS 0x0000010A
|
||||
|
||||
/* Protocol-independent codes generated by the Connection Broker */
|
||||
#define ERRINFO_CB_DESTINATION_NOT_FOUND 0x0000400
|
||||
#define ERRINFO_CB_LOADING_DESTINATION 0x0000402
|
||||
#define ERRINFO_CB_REDIRECTING_TO_DESTINATION 0x0000404
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_WAKE 0x0000405
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT 0x0000406
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS 0x0000407
|
||||
#define ERRINFO_CB_DESTINATION_POOL_NOT_FREE 0x0000408
|
||||
#define ERRINFO_CB_CONNECTION_CANCELLED 0x0000409
|
||||
#define ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS 0x0000410
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT 0x0000411
|
||||
#define ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED 0x0000412
|
||||
|
||||
/* RDP specific codes */
|
||||
#define ERRINFO_UNKNOWN_DATA_PDU_TYPE 0x000010C9
|
||||
#define ERRINFO_UNKNOWN_PDU_TYPE 0x000010CA
|
||||
@ -134,6 +134,7 @@ extern "C" {
|
||||
#define ERRINFO_BAD_MONITOR_DATA 0x00001129
|
||||
#define ERRINFO_VC_DECOMPRESSED_REASSEMBLE_FAILED 0x0000112A
|
||||
#define ERRINFO_VC_DATA_TOO_LONG 0x0000112B
|
||||
#define ERRINFO_BAD_FRAME_ACK_DATA 0x0000112C
|
||||
#define ERRINFO_GRAPHICS_MODE_NOT_SUPPORTED 0x0000112D
|
||||
#define ERRINFO_GRAPHICS_SUBSYSTEM_RESET_FAILED 0x0000112E
|
||||
#define ERRINFO_GRAPHICS_SUBSYSTEM_FAILED 0x0000112F
|
||||
@ -141,6 +142,9 @@ extern "C" {
|
||||
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_LONG 0x00001131
|
||||
#define ERRINFO_DYNAMIC_DST_DISABLED_FIELD_MISSING 0x00001132
|
||||
#define ERRINFO_VC_DECODING_ERROR 0x00001133
|
||||
#define ERRINFO_VIRTUALDESKTOPTOOLARGE 0x00001134
|
||||
#define ERRINFO_MONITORGEOMETRYVALIDATIONFAILED 0x00001135
|
||||
#define ERRINFO_INVALIDMONITORCOUNT 0x00001136
|
||||
#define ERRINFO_UPDATE_SESSION_KEY_FAILED 0x00001191
|
||||
#define ERRINFO_DECRYPT_FAILED 0x00001192
|
||||
#define ERRINFO_ENCRYPT_FAILED 0x00001193
|
||||
|
||||
@ -59,6 +59,14 @@ typedef RDP_CLIENT_ENTRY_POINTS_V1 RDP_CLIENT_ENTRY_POINTS;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Flags used by certificate callbacks */
|
||||
#define VERIFY_CERT_FLAG_NONE 0x00
|
||||
#define VERIFY_CERT_FLAG_LEGACY 0x02
|
||||
#define VERIFY_CERT_FLAG_REDIRECT 0x10
|
||||
#define VERIFY_CERT_FLAG_GATEWAY 0x20
|
||||
#define VERIFY_CERT_FLAG_CHANGED 0x40
|
||||
#define VERIFY_CERT_FLAG_MISMATCH 0x80
|
||||
|
||||
typedef BOOL (*pContextNew)(freerdp* instance, rdpContext* context);
|
||||
typedef void (*pContextFree)(freerdp* instance, rdpContext* context);
|
||||
|
||||
@ -71,6 +79,7 @@ typedef BOOL (*pAuthenticate)(freerdp* instance, char** username,
|
||||
/** @brief Callback used if user interaction is required to accept
|
||||
* an unknown certificate.
|
||||
*
|
||||
* @deprecated Use pVerifyCertificateEx
|
||||
* @param common_name The certificate registered hostname.
|
||||
* @param subject The common name of the certificate.
|
||||
* @param issuer The issuer of the certificate.
|
||||
@ -88,9 +97,33 @@ typedef DWORD (*pVerifyCertificate)(freerdp* instance,
|
||||
const char* fingerprint,
|
||||
BOOL host_mismatch);
|
||||
|
||||
/** @brief Callback used if user interaction is required to accept
|
||||
* an unknown certificate.
|
||||
*
|
||||
* @param host The hostname connecting to.
|
||||
* @param port The port connecting to.
|
||||
* @param common_name The certificate registered hostname.
|
||||
* @param subject The common name of the certificate.
|
||||
* @param issuer The issuer of the certificate.
|
||||
* @param fingerprint The fingerprint of the certificate.
|
||||
* @param flags Flags of type VERIFY_CERT_FLAG*
|
||||
*
|
||||
* @return 1 to accept and store a certificate, 2 to accept
|
||||
* a certificate only for this session, 0 otherwise.
|
||||
*/
|
||||
typedef DWORD (*pVerifyCertificateEx)(freerdp* instance,
|
||||
const char* host,
|
||||
UINT16 port,
|
||||
const char* common_name,
|
||||
const char* subject,
|
||||
const char* issuer,
|
||||
const char* fingerprint,
|
||||
DWORD flags);
|
||||
|
||||
/** @brief Callback used if user interaction is required to accept
|
||||
* a changed certificate.
|
||||
*
|
||||
* @deprecated Use pVerifyChangedCertificateEx
|
||||
* @param common_name The certificate registered hostname.
|
||||
* @param subject The common name of the new certificate.
|
||||
* @param issuer The issuer of the new certificate.
|
||||
@ -111,9 +144,53 @@ typedef DWORD (*pVerifyChangedCertificate)(freerdp* instance,
|
||||
const char* old_subject,
|
||||
const char* old_issuer,
|
||||
const char* old_fingerprint);
|
||||
typedef int (*pVerifyX509Certificate)(freerdp* instance, BYTE* data,
|
||||
int length, const char* hostname,
|
||||
int port, DWORD flags);
|
||||
|
||||
/** @brief Callback used if user interaction is required to accept
|
||||
* a changed certificate.
|
||||
*
|
||||
* @param host The hostname connecting to.
|
||||
* @param port The port connecting to.
|
||||
* @param common_name The certificate registered hostname.
|
||||
* @param subject The common name of the new certificate.
|
||||
* @param issuer The issuer of the new certificate.
|
||||
* @param fingerprint The fingerprint of the new certificate.
|
||||
* @param old_subject The common name of the old certificate.
|
||||
* @param old_issuer The issuer of the new certificate.
|
||||
* @param old_fingerprint The fingerprint of the old certificate.
|
||||
* @param flags Flags of type VERIFY_CERT_FLAG*
|
||||
*
|
||||
* @return 1 to accept and store a certificate, 2 to accept
|
||||
* a certificate only for this session, 0 otherwise.
|
||||
*/
|
||||
|
||||
typedef DWORD (*pVerifyChangedCertificateEx)(freerdp* instance,
|
||||
const char* host,
|
||||
UINT16 port,
|
||||
const char* common_name,
|
||||
const char* subject,
|
||||
const char* issuer,
|
||||
const char* new_fingerprint,
|
||||
const char* old_subject,
|
||||
const char* old_issuer,
|
||||
const char* old_fingerprint,
|
||||
DWORD flags);
|
||||
|
||||
/** @brief Callback used if user interaction is required to accept
|
||||
* a certificate.
|
||||
*
|
||||
* @param instance Pointer to the freerdp instance.
|
||||
* @param data Pointer to certificate data in PEM format.
|
||||
* @param length The length of the certificate data.
|
||||
* @param hostname The hostname connecting to.
|
||||
* @param port The port connecting to.
|
||||
* @param flags Flags of type VERIFY_CERT_FLAG*
|
||||
*
|
||||
* @return 1 to accept and store a certificate, 2 to accept
|
||||
* a certificate only for this session, 0 otherwise.
|
||||
*/
|
||||
typedef int (*pVerifyX509Certificate)(freerdp* instance, const BYTE* data,
|
||||
size_t length, const char* hostname,
|
||||
UINT16 port, DWORD flags);
|
||||
|
||||
typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type);
|
||||
|
||||
@ -122,6 +199,9 @@ typedef int (*pSendChannelData)(freerdp* instance, UINT16 channelId, BYTE* data,
|
||||
typedef int (*pReceiveChannelData)(freerdp* instance, UINT16 channelId,
|
||||
BYTE* data, int size, int flags, int totalSize);
|
||||
|
||||
typedef BOOL (*pPresentGatewayMessage)(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
|
||||
BOOL isConsentMandatory, size_t length, const WCHAR* message);
|
||||
|
||||
/**
|
||||
* Defines the context for a given instance of RDP connection.
|
||||
* It is embedded in the rdp_freerdp structure, and allocated by a call to freerdp_context_new().
|
||||
@ -274,11 +354,12 @@ struct rdp_freerdp
|
||||
It is used to get the username/password when it was not provided at connection time. */
|
||||
ALIGN64 pVerifyCertificate VerifyCertificate; /**< (offset 51)
|
||||
Callback for certificate validation.
|
||||
Used to verify that an unknown certificate is trusted. */
|
||||
Used to verify that an unknown certificate is trusted.
|
||||
DEPRECATED: Use VerifyChangedCertificateEx*/
|
||||
ALIGN64 pVerifyChangedCertificate VerifyChangedCertificate; /**< (offset 52)
|
||||
Callback for changed certificate validation.
|
||||
Used when a certificate differs from stored fingerprint.
|
||||
If returns TRUE, the new fingerprint will be trusted and old thrown out. */
|
||||
DEPRECATED: Use VerifyChangedCertificateEx */
|
||||
|
||||
ALIGN64 pVerifyX509Certificate
|
||||
VerifyX509Certificate; /**< (offset 53) Callback for X509 certificate verification (PEM format) */
|
||||
@ -294,7 +375,11 @@ struct rdp_freerdp
|
||||
Callback for gateway authentication.
|
||||
It is used to get the username/password when it was not provided at connection time. */
|
||||
|
||||
UINT64 paddingD[64 - 57]; /* 57 */
|
||||
ALIGN64 pPresentGatewayMessage PresentGatewayMessage;/**< (offset 57)
|
||||
Callback for gateway consent messages.
|
||||
It is used to present consent messages to the user. */
|
||||
|
||||
UINT64 paddingD[64 - 58]; /* 58 */
|
||||
|
||||
ALIGN64 pSendChannelData SendChannelData; /* (offset 64)
|
||||
Callback for sending data to a channel.
|
||||
@ -305,7 +390,13 @@ struct rdp_freerdp
|
||||
This is called by freerdp_channel_process() (if not NULL).
|
||||
Clients will typically use a function that calls freerdp_channels_data() to perform the needed tasks. */
|
||||
|
||||
UINT64 paddingE[80 - 66]; /* 66 */
|
||||
ALIGN64 pVerifyCertificateEx VerifyCertificateEx; /**< (offset 66)
|
||||
Callback for certificate validation.
|
||||
Used to verify that an unknown certificate is trusted. */
|
||||
ALIGN64 pVerifyChangedCertificateEx VerifyChangedCertificateEx; /**< (offset 67)
|
||||
Callback for changed certificate validation.
|
||||
Used when a certificate differs from stored fingerprint. */
|
||||
UINT64 paddingE[80 - 68]; /* 68 */
|
||||
};
|
||||
|
||||
struct rdp_channel_handles
|
||||
|
||||
@ -27,7 +27,7 @@ struct gdi_gfx_surface
|
||||
{
|
||||
UINT16 surfaceId;
|
||||
rdpCodecs* codecs;
|
||||
H264_CONTEXT *h264;
|
||||
H264_CONTEXT* h264;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BYTE* data;
|
||||
@ -55,7 +55,7 @@ typedef struct gdi_gfx_cache_entry gdiGfxCacheEntry;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FREERDP_API void gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx);
|
||||
FREERDP_API BOOL gdi_graphics_pipeline_init(rdpGdi* gdi, RdpgfxClientContext* gfx);
|
||||
FREERDP_API void gdi_graphics_pipeline_uninit(rdpGdi* gdi, RdpgfxClientContext* gfx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
160
include/freerdp/license.h
Normal file
160
include/freerdp/license.h
Normal file
@ -0,0 +1,160 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Licensing API
|
||||
*
|
||||
* Copyright 2018 David Fort <contact@hardening-consulting.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_LICENSE_H
|
||||
#define FREERDP_LICENSE_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
|
||||
typedef struct rdp_license rdpLicense;
|
||||
|
||||
/** @brief Licensing Packet Types */
|
||||
enum
|
||||
{
|
||||
LICENSE_REQUEST = 0x01,
|
||||
PLATFORM_CHALLENGE = 0x02,
|
||||
NEW_LICENSE = 0x03,
|
||||
UPGRADE_LICENSE = 0x04,
|
||||
LICENSE_INFO = 0x12,
|
||||
NEW_LICENSE_REQUEST = 0x13,
|
||||
PLATFORM_CHALLENGE_RESPONSE = 0x15,
|
||||
ERROR_ALERT = 0xFF
|
||||
};
|
||||
|
||||
#define LICENSE_PKT_CS_MASK (LICENSE_INFO | NEW_LICENSE_REQUEST | PLATFORM_CHALLENGE_RESPONSE | ERROR_ALERT)
|
||||
#define LICENSE_PKT_SC_MASK (LICENSE_REQUEST | PLATFORM_CHALLENGE | NEW_LICENSE | UPGRADE_LICENSE | ERROR_ALERT)
|
||||
#define LICENSE_PKT_MASK (LICENSE_PKT_CS_MASK | LICENSE_PKT_SC_MASK)
|
||||
|
||||
#define LICENSE_PREAMBLE_LENGTH 4
|
||||
|
||||
/* Cryptographic Lengths */
|
||||
|
||||
#define CLIENT_RANDOM_LENGTH 32
|
||||
#define SERVER_RANDOM_LENGTH 32
|
||||
#define MASTER_SECRET_LENGTH 48
|
||||
#define PREMASTER_SECRET_LENGTH 48
|
||||
#define SESSION_KEY_BLOB_LENGTH 48
|
||||
#define MAC_SALT_KEY_LENGTH 16
|
||||
#define LICENSING_ENCRYPTION_KEY_LENGTH 16
|
||||
#define HWID_PLATFORM_ID_LENGTH 4
|
||||
#define HWID_UNIQUE_DATA_LENGTH 16
|
||||
#define HWID_LENGTH 20
|
||||
#define LICENSING_PADDING_SIZE 8
|
||||
|
||||
/* Preamble Flags */
|
||||
|
||||
#define PREAMBLE_VERSION_2_0 0x02
|
||||
#define PREAMBLE_VERSION_3_0 0x03
|
||||
#define LicenseProtocolVersionMask 0x0F
|
||||
#define EXTENDED_ERROR_MSG_SUPPORTED 0x80
|
||||
|
||||
/** @brief binary Blob Types */
|
||||
enum
|
||||
{
|
||||
BB_ANY_BLOB = 0x0000,
|
||||
BB_DATA_BLOB = 0x0001,
|
||||
BB_RANDOM_BLOB = 0x0002,
|
||||
BB_CERTIFICATE_BLOB = 0x0003,
|
||||
BB_ERROR_BLOB = 0x0004,
|
||||
BB_ENCRYPTED_DATA_BLOB = 0x0009,
|
||||
BB_KEY_EXCHG_ALG_BLOB = 0x000D,
|
||||
BB_SCOPE_BLOB = 0x000E,
|
||||
BB_CLIENT_USER_NAME_BLOB = 0x000F,
|
||||
BB_CLIENT_MACHINE_NAME_BLOB = 0x0010
|
||||
};
|
||||
|
||||
/* License Key Exchange Algorithms */
|
||||
|
||||
#define KEY_EXCHANGE_ALG_RSA 0x00000001
|
||||
|
||||
/** @brief license Error Codes */
|
||||
enum
|
||||
{
|
||||
ERR_INVALID_SERVER_CERTIFICATE = 0x00000001,
|
||||
ERR_NO_LICENSE = 0x00000002,
|
||||
ERR_INVALID_MAC = 0x00000003,
|
||||
ERR_INVALID_SCOPE = 0x00000004,
|
||||
ERR_NO_LICENSE_SERVER = 0x00000006,
|
||||
STATUS_VALID_CLIENT = 0x00000007,
|
||||
ERR_INVALID_CLIENT = 0x00000008,
|
||||
ERR_INVALID_PRODUCT_ID = 0x0000000B,
|
||||
ERR_INVALID_MESSAGE_LENGTH = 0x0000000C
|
||||
};
|
||||
|
||||
/** @brief state Transition Codes */
|
||||
enum
|
||||
{
|
||||
ST_TOTAL_ABORT = 0x00000001,
|
||||
ST_NO_TRANSITION = 0x00000002,
|
||||
ST_RESET_PHASE_TO_START = 0x00000003,
|
||||
ST_RESEND_LAST_MESSAGE = 0x00000004
|
||||
};
|
||||
|
||||
/** @brief Platform Challenge Types */
|
||||
enum
|
||||
{
|
||||
WIN32_PLATFORM_CHALLENGE_TYPE = 0x0100,
|
||||
WIN16_PLATFORM_CHALLENGE_TYPE = 0x0200,
|
||||
WINCE_PLATFORM_CHALLENGE_TYPE = 0x0300,
|
||||
OTHER_PLATFORM_CHALLENGE_TYPE = 0xFF00
|
||||
};
|
||||
|
||||
/** @brief License Detail Levels */
|
||||
enum
|
||||
{
|
||||
LICENSE_DETAIL_SIMPLE = 0x0001,
|
||||
LICENSE_DETAIL_MODERATE = 0x0002,
|
||||
LICENSE_DETAIL_DETAIL = 0x0003
|
||||
};
|
||||
|
||||
/*
|
||||
* PlatformId:
|
||||
*
|
||||
* The most significant byte of the PlatformId field contains the operating system version of the client.
|
||||
* The second most significant byte of the PlatformId field identifies the ISV that provided the client image.
|
||||
* The remaining two bytes in the PlatformId field are used by the ISV to identify the build number of the operating system.
|
||||
*
|
||||
* 0x04010000:
|
||||
*
|
||||
* CLIENT_OS_ID_WINNT_POST_52 (0x04000000)
|
||||
* CLIENT_IMAGE_ID_MICROSOFT (0x00010000)
|
||||
*/
|
||||
enum
|
||||
{
|
||||
CLIENT_OS_ID_WINNT_351 = 0x01000000,
|
||||
CLIENT_OS_ID_WINNT_40 = 0x02000000,
|
||||
CLIENT_OS_ID_WINNT_50 = 0x03000000,
|
||||
CLIENT_OS_ID_WINNT_POST_52 = 0x04000000,
|
||||
|
||||
CLIENT_IMAGE_ID_MICROSOFT = 0x00010000,
|
||||
CLIENT_IMAGE_ID_CITRIX = 0x00020000,
|
||||
};
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FREERDP_API BOOL license_send_valid_client_error_packet(rdpRdp* rdp);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LICENSE_H */
|
||||
@ -67,6 +67,17 @@ typedef int (*psPeerVirtualChannelWrite)(freerdp_peer* peer, HANDLE hChannel, BY
|
||||
typedef void* (*psPeerVirtualChannelGetData)(freerdp_peer* peer, HANDLE hChannel);
|
||||
typedef int (*psPeerVirtualChannelSetData)(freerdp_peer* peer, HANDLE hChannel, void* data);
|
||||
|
||||
/** @brief the result of the license callback */
|
||||
typedef enum
|
||||
{
|
||||
LICENSE_CB_INTERNAL_ERROR, /** an internal error happened in the callback */
|
||||
LICENSE_CB_ABORT, /** licensing process failed, abort the connection */
|
||||
LICENSE_CB_IN_PROGRESS, /** incoming packet has been treated, we're waiting for further packets to complete the workflow */
|
||||
LICENSE_CB_COMPLETED /** the licensing workflow has completed, go to next step */
|
||||
} LicenseCallbackResult;
|
||||
|
||||
typedef LicenseCallbackResult (*psPeerLicenseCallback)(freerdp_peer* peer, wStream* s);
|
||||
|
||||
|
||||
struct rdp_freerdp_peer
|
||||
{
|
||||
@ -123,6 +134,7 @@ struct rdp_freerdp_peer
|
||||
psPeerAdjustMonitorsLayout AdjustMonitorsLayout;
|
||||
psPeerClientCapabilities ClientCapabilities;
|
||||
psPeerComputeNtlmHash ComputeNtlmHash;
|
||||
psPeerLicenseCallback LicenseCallback;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#define RAIL_EXEC_FLAG_TRANSLATE_FILES 0x0002
|
||||
#define RAIL_EXEC_FLAG_FILE 0x0004
|
||||
#define RAIL_EXEC_FLAG_EXPAND_ARGUMENTS 0x0008
|
||||
#define RAIL_EXEC_FLAG_APP_USER_MODEL_ID 0x0010
|
||||
|
||||
/* Server Execute Result PDU */
|
||||
#define RAIL_EXEC_S_OK 0x0000
|
||||
|
||||
@ -682,6 +682,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
|
||||
#define FreeRDP_PrivateKeyContent (1417)
|
||||
#define FreeRDP_RdpKeyContent (1418)
|
||||
#define FreeRDP_AutoAcceptCertificate (1419)
|
||||
#define FreeRDP_AutoDenyCertificate (1420)
|
||||
#define FreeRDP_Workarea (1536)
|
||||
#define FreeRDP_Fullscreen (1537)
|
||||
#define FreeRDP_PercentScreen (1538)
|
||||
@ -709,6 +710,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
|
||||
#define FreeRDP_AuthenticationOnly (1603)
|
||||
#define FreeRDP_CredentialsFromStdin (1604)
|
||||
#define FreeRDP_UnmapButtons (1605)
|
||||
#define FreeRDP_OldLicenseBehaviour (1606)
|
||||
#define FreeRDP_ComputerName (1664)
|
||||
#define FreeRDP_ConnectionFile (1728)
|
||||
#define FreeRDP_AssistanceFile (1729)
|
||||
@ -1135,7 +1137,8 @@ struct rdp_settings
|
||||
ALIGN64 char* PrivateKeyContent; /* 1417 */
|
||||
ALIGN64 char* RdpKeyContent; /* 1418 */
|
||||
ALIGN64 BOOL AutoAcceptCertificate; /* 1419 */
|
||||
UINT64 padding1472[1472 - 1420]; /* 1420 */
|
||||
ALIGN64 BOOL AutoDenyCertificate; /* 1420 */
|
||||
UINT64 padding1472[1472 - 1421]; /* 1421 */
|
||||
UINT64 padding1536[1536 - 1472]; /* 1472 */
|
||||
|
||||
/**
|
||||
@ -1518,7 +1521,7 @@ struct rdp_settings
|
||||
ALIGN64 BYTE*
|
||||
SettingsModified; /* byte array marking fields that have been modified from their default value */
|
||||
ALIGN64 char* ActionScript;
|
||||
ALIGN64 BOOL Floatbar;
|
||||
ALIGN64 DWORD Floatbar;
|
||||
|
||||
};
|
||||
typedef struct rdp_settings rdpSettings;
|
||||
|
||||
@ -139,6 +139,20 @@ enum SURFCMD_FRAMEACTION
|
||||
SURFACECMD_FRAMEACTION_END = 0x0001
|
||||
};
|
||||
|
||||
/** @brief status code as in 2.2.5.2 Server Status Info PDU */
|
||||
enum
|
||||
{
|
||||
TS_STATUS_FINDING_DESTINATION = 0x00000401,
|
||||
TS_STATUS_LOADING_DESTINATION = 0x00000402,
|
||||
TS_STATUS_BRINGING_SESSION_ONLINE = 0x00000403,
|
||||
TS_STATUS_REDIRECTING_TO_DESTINATION = 0x00000404,
|
||||
TS_STATUS_VM_LOADING = 0x00000501,
|
||||
TS_STATUS_VM_WAKING = 0x00000502,
|
||||
TS_STATUS_VM_STARTING = 0x00000503,
|
||||
TS_STATUS_VM_STARTING_MONITORING = 0x00000504,
|
||||
TS_STATUS_VM_RETRYING_MONITORING = 0x00000505
|
||||
};
|
||||
|
||||
struct _SURFACE_FRAME
|
||||
{
|
||||
UINT32 frameId;
|
||||
@ -180,6 +194,7 @@ typedef BOOL (*pSurfaceFrameAcknowledge)(rdpContext* context, UINT32 frameId);
|
||||
typedef BOOL (*pSaveSessionInfo)(rdpContext* context, UINT32 type, void* data);
|
||||
typedef BOOL (*pSetKeyboardImeStatus)(rdpContext* context, UINT16 imeId, UINT32 imeState,
|
||||
UINT32 imeConvMode);
|
||||
typedef BOOL (*pServerStatusInfo)(rdpContext* context, UINT32 status);
|
||||
|
||||
struct rdp_update
|
||||
{
|
||||
@ -216,7 +231,8 @@ struct rdp_update
|
||||
pSurfaceFrameBits SurfaceFrameBits; /* 67 */
|
||||
pSurfaceFrameAcknowledge SurfaceFrameAcknowledge; /* 68 */
|
||||
pSaveSessionInfo SaveSessionInfo; /* 69 */
|
||||
UINT32 paddingE[80 - 70]; /* 70 */
|
||||
pServerStatusInfo ServerStatusInfo; /* 70 */
|
||||
UINT32 paddingE[80 - 71]; /* 71 */
|
||||
|
||||
/* internal */
|
||||
|
||||
|
||||
@ -206,7 +206,9 @@ endif()
|
||||
if(WITH_OPENH264)
|
||||
set(CODEC_SRCS ${CODEC_SRCS} codec/h264_openh264.c)
|
||||
freerdp_include_directory_add(${OPENH264_INCLUDE_DIR})
|
||||
freerdp_library_add(${OPENH264_LIBRARIES})
|
||||
if (NOT WITH_OPENH264_LOADING)
|
||||
freerdp_library_add(${OPENH264_LIBRARIES})
|
||||
endif (NOT WITH_OPENH264_LOADING)
|
||||
endif()
|
||||
|
||||
if(WITH_FFMPEG)
|
||||
|
||||
6
libfreerdp/cache/glyph.c
vendored
6
libfreerdp/cache/glyph.c
vendored
@ -796,6 +796,9 @@ CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context, const CACHE_GLYPH
|
||||
|
||||
if (glyph->unicodeCharacters)
|
||||
{
|
||||
if (glyph->cGlyphs == 0)
|
||||
goto fail;
|
||||
|
||||
dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
|
||||
|
||||
if (!dst->unicodeCharacters)
|
||||
@ -855,6 +858,9 @@ CACHE_GLYPH_V2_ORDER* copy_cache_glyph_v2_order(rdpContext* context,
|
||||
|
||||
if (glyph->unicodeCharacters)
|
||||
{
|
||||
if (glyph->cGlyphs == 0)
|
||||
goto fail;
|
||||
|
||||
dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
|
||||
|
||||
if (!dst->unicodeCharacters)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user