From 89f3a8a71e0cf5ae9a1154cc168be7ebd97a64e7 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 2 Aug 2024 15:45:33 +1000 Subject: [PATCH] Add support for FreeRDP 3.x With this, Weston can build against either FreeRDP 3.x or 2.x depending on what has been detected by meson (3.x takes priority). The main source of changes is the settings are now opaque and require the use of accessors. That was pretty mechanical and seems to work on 2.x as well. There are a few changes around constants getting a WINPR_ prefix, the UTF conversion functions we used are obsolete, so use the proper "new" ones, and other fairly minor things. The key & cert management changed rather completely, libfreerdp won't load files for us, we have to use the helpers to do so, and I *think* the RDP RSA key and SSL key use the same setting location. Seems to work with SSL at least. There was also a minor glitch with keyboard input, KBD_FLAGS_DOWN is basically never set. It appears to be an upstream FreeRDP change in 3.x, it was being set incorrectly (always on any key down) while it should only be set on repeats. However the fastpath input code has no way to set it from what I can tell, so it's just loss. We instead ignore it. Note that the screen size is odd (and different between freerdp client and remmina), it also won't adjust dynamically when the window is resized. I don't think this relates to my port though, I observe the same behaviour with the packaged FreeRDP 2 based Weston, but I can try to look into it later Signed-off-by: Benjamin Herrenschmidt --- .gitlab-ci.yml | 13 +- .gitlab-ci/debian-install.sh | 7 +- libweston/backend-rdp/meson.build | 68 +++++---- libweston/backend-rdp/rdp.c | 226 +++++++++++++++++++----------- libweston/backend-rdp/rdp.h | 21 +++ libweston/backend-rdp/rdpclip.c | 65 ++++++--- 6 files changed, 271 insertions(+), 129 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a72b24f3..90101c07 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -43,7 +43,7 @@ variables: FDO_UPSTREAM_REPO: wayland/weston FDO_REPO_SUFFIX: "$BUILD_OS-$FDO_DISTRIBUTION_VERSION/$BUILD_ARCH" - FDO_DISTRIBUTION_TAG: '2024-08-05-00-rm-plugins' + FDO_DISTRIBUTION_TAG: '2024-08-14-00-freerdp3.x' include: @@ -89,6 +89,7 @@ stages: variables: BUILD_OS: debian LLVM_VERSION: 11 + FREERDP_VERSION: 2 FDO_DISTRIBUTION_VERSION: bullseye FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} bash .gitlab-ci/debian-install.sh' @@ -96,6 +97,8 @@ stages: variables: BUILD_OS: debian LLVM_VERSION: 15 + FREERDP_VERSION: 3 + USE_BOOKWORM_BACKPORTS: y # If you upgrade from bookworm, see the use_tls=0 notes in tests/meson.build. FDO_DISTRIBUTION_VERSION: bookworm FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} BUILD_ARCH=${BUILD_ARCH} KERNEL_IMAGE=${KERNEL_IMAGE} KERNEL_DEFCONFIG=${KERNEL_DEFCONFIG} LLVM_VERSION=${LLVM_VERSION} FDO_DISTRIBUTION_VERSION=${FDO_DISTRIBUTION_VERSION} bash .gitlab-ci/debian-install.sh' @@ -142,6 +145,10 @@ check-commit: - .os-debian variables: BUILD_ARCH: "armv7" + # Armv7 doesn't have freerdp3 in bookworm-backports so we don't build FreeRDP + MESON_DIST_OPTIONS: "-Dbackend-rdp=false" + # Inhibit installation of freerdp-dev + FREERDP_VERSION: 0 .debian-lts-aarch64: extends: @@ -276,7 +283,7 @@ aarch64-debian-container_prep: - .default-rules script: - cd "$BUILDDIR" - - meson --prefix="$PREFIX" --wrap-mode=nofallback -Db_sanitize=address ${MESON_OPTIONS} ${MESON_TOOLCHAIN_OPTIONS} .. + - meson --prefix="$PREFIX" --wrap-mode=nofallback -Db_sanitize=address ${MESON_OPTIONS} ${MESON_TOOLCHAIN_OPTIONS} ${MESON_DIST_OPTIONS} .. - ninja -k0 -j${FDO_CI_CONCURRENT:-4} - ninja install - test -n "${QEMU_SMP}" || QEMU_SMP=${FDO_CI_CONCURRENT:-4} @@ -304,7 +311,7 @@ aarch64-debian-container_prep: - .default-rules script: - cd "$BUILDDIR" - - meson --prefix="$PREFIX" --wrap-mode=nofallback ${MESON_OPTIONS} .. + - meson --prefix="$PREFIX" --wrap-mode=nofallback ${MESON_OPTIONS} ${MESON_DIST_OPTIONS} .. - ninja -k0 -j${FDO_CI_CONCURRENT:-4} - ninja install - ninja clean diff --git a/.gitlab-ci/debian-install.sh b/.gitlab-ci/debian-install.sh index 6999097b..e9c512cb 100644 --- a/.gitlab-ci/debian-install.sh +++ b/.gitlab-ci/debian-install.sh @@ -31,6 +31,9 @@ MESA_RUNTIME_PKGS=" libllvm${LLVM_VERSION} " +if [ x"$USE_BOOKWORM_BACKPORTS" = "xy" ] ; then + echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list +fi apt-get update apt-get -y --no-install-recommends install \ autoconf \ @@ -40,7 +43,6 @@ apt-get -y --no-install-recommends install \ curl \ doxygen \ graphviz \ - freerdp2-dev \ gcovr \ git \ hwdata \ @@ -123,6 +125,9 @@ apt-get -y --no-install-recommends install \ $MESA_RUNTIME_PKGS \ $LINUX_DEV_PKGS \ +if [ "$FREERDP_VERSION" -ne 0 ] ; then + apt-get -y --no-install-recommends install freerdp${FREERDP_VERSION}-dev +fi # Actually build our dependencies ... ./.gitlab-ci/build-deps.sh diff --git a/libweston/backend-rdp/meson.build b/libweston/backend-rdp/meson.build index 4245252c..81f1e12a 100644 --- a/libweston/backend-rdp/meson.build +++ b/libweston/backend-rdp/meson.build @@ -1,46 +1,64 @@ if not get_option('backend-rdp') - subdir_done() + subdir_done() endif config_h.set('BUILD_RDP_COMPOSITOR', '1') -dep_frdp = dependency('freerdp2', version: '>= 2.3.0', required: false) -if not dep_frdp.found() - error('RDP-backend requires freerdp >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') -endif +dep_frdp3 = dependency('freerdp3', version: '>= 3.0.0', required: false) +dep_frdp2 = dependency('freerdp2', version: '>= 2.3.0', required: false) -dep_frdp_server = dependency('freerdp-server2', version: '>= 2.3.0', required: false) -if not dep_frdp_server.found() - error('RDP-backend requires freerdp-server2 >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') -endif +if dep_frdp3.found() + config_h.set('USE_FREERDP_VERSION', '3') + dep_frdp = dep_frdp3 + dep_frdp_server = dependency('freerdp-server3', version: '>= 3.0.0', required: false) + if not dep_frdp_server.found() + error('RDP-backend v3 requires freerdp-server3 >= 3.0.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') + endif -dep_wpr = dependency('winpr2', version: '>= 2.3.0', required: false) -if not dep_wpr.found() - error('RDP-backend requires winpr >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') + dep_wpr = dependency('winpr3', version: '>= 3.0.0', required: false) + if not dep_wpr.found() + error('RDP-backend v3 requires winpr >= 3.0.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') + endif + message('Using FreeRDP 3.x for RDP backend') +elif dep_frdp2.found() + config_h.set('USE_FREERDP_VERSION', '2') + dep_frdp = dep_frdp2 + dep_frdp_server = dependency('freerdp-server2', version: '>= 2.3.0', required: false) + if not dep_frdp_server.found() + error('RDP-backend v2 requires freerdp-server2 >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') + endif + + dep_wpr = dependency('winpr2', version: '>= 2.3.0', required: false) + if not dep_wpr.found() + error('RDP-backend requires v2 winpr >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') + endif + message('Using FreeRDP 2.x for RDP backend') +else + error('RDP-backend requires freerdp3 >= 3.0.0 or freerdp2 >= 2.3.0 which was not found. Or, you can use \'-Dbackend-rdp=false\'.') endif deps_rdp = [ - dep_libweston_private, - dep_frdp, - dep_frdp_server, - dep_wpr, - dep_libdrm_headers, + dep_libweston_private, + dep_frdp, + dep_frdp_server, + dep_wpr, + dep_libdrm_headers, ] srcs_rdp = [ 'rdp.c', 'rdpclip.c', - 'rdpdisp.c', + 'rdpdisp.c', 'rdputil.c', ] plugin_rdp = shared_library( - 'rdp-backend', - srcs_rdp, - include_directories: common_inc, - dependencies: deps_rdp, - name_prefix: '', - install: true, - install_dir: dir_module_libweston + 'rdp-backend', + srcs_rdp, + include_directories: common_inc, + dependencies: deps_rdp, + name_prefix: '', + install: true, + install_dir: dir_module_libweston ) env_modmap += 'rdp-backend.so=@0@;'.format(plugin_rdp.full_path()) install_headers(backend_rdp_h, subdir: dir_include_libweston_install) diff --git a/libweston/backend-rdp/rdp.c b/libweston/backend-rdp/rdp.c index 7267ceca..0059b418 100644 --- a/libweston/backend-rdp/rdp.c +++ b/libweston/backend-rdp/rdp.c @@ -100,7 +100,7 @@ rdp_peer_refresh_rfx(pixman_region32_t *damage, pixman_image_t *image, freerdp_p cmd.destRight = damage->extents.x2; cmd.destBottom = damage->extents.y2; cmd.bmp.bpp = 32; - cmd.bmp.codecID = peer->context->settings->RemoteFxCodecId; + cmd.bmp.codecID = freerdp_settings_get_uint32(peer->context->settings, FreeRDP_RemoteFxCodecId); cmd.bmp.width = width; cmd.bmp.height = height; @@ -161,7 +161,7 @@ rdp_peer_refresh_nsc(pixman_region32_t *damage, pixman_image_t *image, freerdp_p cmd.destRight = damage->extents.x2; cmd.destBottom = damage->extents.y2; cmd.bmp.bpp = 32; - cmd.bmp.codecID = peer->context->settings->NSCodecId; + cmd.bmp.codecID = freerdp_settings_get_uint32(peer->context->settings, FreeRDP_NSCodecId); cmd.bmp.width = width; cmd.bmp.height = height; @@ -220,7 +220,8 @@ rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp_p cmd.destRight = rect->x2; cmd.bmp.width = (rect->x2 - rect->x1); - heightIncrement = peer->context->settings->MultifragMaxRequestSize / (16 + cmd.bmp.width * 4); + heightIncrement = freerdp_settings_get_uint32(peer->context->settings, + FreeRDP_MultifragMaxRequestSize) / (16 + cmd.bmp.width * 4); remainingHeight = rect->y2 - rect->y1; top = rect->y1; @@ -259,9 +260,9 @@ rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer) struct rdp_output *output = rdp_get_first_output(context->rdpBackend); rdpSettings *settings = peer->context->settings; - if (settings->RemoteFxCodec) + if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec)) rdp_peer_refresh_rfx(region, output->shadow_surface, peer); - else if (settings->NSCodec) + else if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec)) rdp_peer_refresh_nsc(region, output->shadow_surface, peer); else rdp_peer_refresh_raw(region, output->shadow_surface, peer); @@ -398,17 +399,17 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode) */ wl_list_for_each(rdpPeer, &b->peers, link) { settings = rdpPeer->peer->context->settings; - if (settings->DesktopWidth == (uint32_t)mode->width && - settings->DesktopHeight == (uint32_t)mode->height) + if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) == (uint32_t)mode->width && + freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) == (uint32_t)mode->height) continue; - if (!settings->DesktopResize) { + if (!freerdp_settings_get_bool(settings, FreeRDP_DesktopResize)) { /* too bad this peer does not support desktop resize */ weston_log("desktop resize is not allowed\n"); rdpPeer->peer->Close(rdpPeer->peer); } else { - settings->DesktopWidth = mode->width; - settings->DesktopHeight = mode->height; + freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, mode->width); + freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, mode->height); rdpPeer->peer->context->update->DesktopResize(rdpPeer->peer->context); } } @@ -758,9 +759,16 @@ rdp_peer_context_new(freerdp_peer* client, RdpPeerContext* context) if (!context->rfx_context) return FALSE; +#if USE_FREERDP_VERSION >= 3 + rfx_context_set_mode(context->rfx_context, RLGR3); + rfx_context_reset(context->rfx_context, + freerdp_settings_get_uint32(client->context->settings, FreeRDP_DesktopWidth), + freerdp_settings_get_uint32(client->context->settings, FreeRDP_DesktopHeight)); +#else context->rfx_context->mode = RLGR3; context->rfx_context->width = client->context->settings->DesktopWidth; context->rfx_context->height = client->context->settings->DesktopHeight; +#endif rfx_context_set_pixel_format(context->rfx_context, DEFAULT_PIXEL_FORMAT); context->nsc_context = nsc_context_new(); @@ -1015,7 +1023,7 @@ convert_rdp_keyboard_to_xkb_rule_names(UINT32 KeyboardType, xkbRuleNames->variant = "kr104"; /* kr(ralt_hangul)/kr(rctrl_hanja) */ else if (KeyboardSubType == 6) /* PC/AT 103 Enhanced Korean Keyboard */ xkbRuleNames->variant = "kr106"; /* kr(hw_keys) */ - } else if (KeyboardType != KBD_TYPE_JAPANESE && ((KeyboardLayout & 0xFFFF) == 0x411)) { + } else if (KeyboardType != WINPR_KBD_TYPE_JAPANESE && ((KeyboardLayout & 0xFFFF) == 0x411)) { /* when Japanese keyboard layout is used without a Japanese 106/109 * keyboard (keyboard type 7), use the "us" layout, since the "jp" * layout in xkb expects the Japanese 106/109 keyboard layout. @@ -1061,6 +1069,8 @@ xf_peer_activate(freerdp_peer* client) char seat_name[50]; POINTER_SYSTEM_UPDATE pointer_system; int width, height; + const char *cl_hostname; + BOOL audio_playback, audio_capture; peerCtx = (RdpPeerContext *)client->context; b = peerCtx->rdpBackend; @@ -1068,31 +1078,32 @@ xf_peer_activate(freerdp_peer* client) output = rdp_get_first_output(b); settings = client->context->settings; - if (!settings->SurfaceCommandsEnabled) { + if (!freerdp_settings_get_bool(settings, FreeRDP_SurfaceCommandsEnabled)) { weston_log("client doesn't support required SurfaceCommands\n"); return FALSE; } - if (b->force_no_compression && settings->CompressionEnabled) { + if (b->force_no_compression && freerdp_settings_get_bool(settings, FreeRDP_CompressionEnabled)) { rdp_debug(b, "Forcing compression off\n"); - settings->CompressionEnabled = FALSE; + freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE); } - settings->AudioPlayback = b->audio_out_setup && b->audio_out_teardown; - settings->AudioCapture = b->audio_in_setup && b->audio_in_teardown; + audio_playback = b->audio_out_setup && b->audio_out_teardown; + freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, audio_playback); + audio_capture = b->audio_in_setup && b->audio_in_teardown; + freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, audio_capture); - if (settings->RedirectClipboard || - settings->AudioPlayback || - settings->AudioCapture) { + if (freerdp_settings_get_bool(settings, FreeRDP_RedirectClipboard) || + audio_playback || audio_capture) { if (!peerCtx->vcm) { weston_log("Virtual channel is required for clipboard, audio playback/capture\n"); goto error_exit; } /* Audio setup will return NULL on failure, and we'll proceed without audio */ - if (settings->AudioPlayback) + if (audio_playback) peerCtx->audio_out_private = b->audio_out_setup(b->compositor, peerCtx->vcm); - if (settings->AudioCapture) + if (audio_capture) peerCtx->audio_in_private = b->audio_in_setup(b->compositor, peerCtx->vcm); } @@ -1103,15 +1114,15 @@ xf_peer_activate(freerdp_peer* client) if (!b->resizeable) { struct weston_mode *mode = output->base.current_mode; - if (mode->width != (int)settings->DesktopWidth || - mode->height != (int)settings->DesktopHeight) { - if (!settings->DesktopResize) { + if (mode->width != (int)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) || + mode->height != (int)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)) { + if (!freerdp_settings_get_bool(settings, FreeRDP_DesktopResize)) { /* peer does not support desktop resize */ weston_log("client doesn't support resizing, closing connection\n"); return FALSE; } else { - settings->DesktopWidth = mode->width; - settings->DesktopHeight = mode->height; + freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, mode->width); + freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, mode->height); client->context->update->DesktopResize(client->context); } } @@ -1130,12 +1141,14 @@ xf_peer_activate(freerdp_peer* client) /* when here it's the first reactivation, we need to setup a little more */ rdp_debug(b, "kbd_layout:0x%x kbd_type:0x%x kbd_subType:0x%x kbd_functionKeys:0x%x\n", - settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType, - settings->KeyboardFunctionKey); + freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout), + freerdp_settings_get_uint32(settings, FreeRDP_KeyboardType), + freerdp_settings_get_uint32(settings, FreeRDP_KeyboardSubType), + freerdp_settings_get_uint32(settings, FreeRDP_KeyboardFunctionKey)); - convert_rdp_keyboard_to_xkb_rule_names(settings->KeyboardType, - settings->KeyboardSubType, - settings->KeyboardLayout, + convert_rdp_keyboard_to_xkb_rule_names(freerdp_settings_get_uint32(settings, FreeRDP_KeyboardType), + freerdp_settings_get_uint32(settings, FreeRDP_KeyboardSubType), + freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout), &xkbRuleNames); keymap = NULL; @@ -1144,10 +1157,12 @@ xf_peer_activate(freerdp_peer* client) &xkbRuleNames, 0); } - if (settings->ClientHostname) - snprintf(seat_name, sizeof(seat_name), "RDP %s", settings->ClientHostname); + cl_hostname = freerdp_settings_get_string(settings, FreeRDP_ClientHostname); + if (cl_hostname) + snprintf(seat_name, sizeof(seat_name), "RDP %s", cl_hostname); else - snprintf(seat_name, sizeof(seat_name), "RDP peer @%s", settings->ClientAddress); + snprintf(seat_name, sizeof(seat_name), "RDP peer @%s", + freerdp_settings_get_string(settings, FreeRDP_ClientAddress)); peersItem->seat = zalloc(sizeof(*peersItem->seat)); if (!peersItem->seat) { @@ -1162,7 +1177,7 @@ xf_peer_activate(freerdp_peer* client) weston_seat_init_pointer(peersItem->seat); /* Initialize RDP clipboard after seat is initialized */ - if (settings->RedirectClipboard) + if (freerdp_settings_get_bool(settings, FreeRDP_RedirectClipboard)) if (rdp_clipboard_init(client) != 0) goto error_exit; @@ -1181,10 +1196,10 @@ error_exit: rdp_clipboard_destroy(peerCtx); - if (settings->AudioPlayback && peerCtx->audio_out_private) + if (audio_playback && peerCtx->audio_out_private) b->audio_out_teardown(peerCtx->audio_out_private); - if (settings->AudioCapture && peerCtx->audio_in_private) + if (audio_capture && peerCtx->audio_in_private) b->audio_in_teardown(peerCtx->audio_in_private); return FALSE; @@ -1502,7 +1517,7 @@ xf_input_synchronize_event(rdpInput *input, UINT32 flags) static BOOL -xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) +xf_input_keyboard_event(rdpInput *input, UINT16 flags, XF_KEV_CODE_TYPE code) { uint32_t scan_code, vk_code, full_code; enum wl_keyboard_key_state keyState; @@ -1512,15 +1527,23 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) int notify = 0; struct timespec time; - if (!(peerContext->item.flags & RDP_PEER_ACTIVATED)) - return TRUE; + rdp_debug_verbose(peerContext->rdpBackend, "RDP backend: %s flags:0x%x, code:0x%x\n", + __func__, flags, code); - if (flags & KBD_FLAGS_DOWN) { - keyState = WL_KEYBOARD_KEY_STATE_PRESSED; - notify = 1; - } else if (flags & KBD_FLAGS_RELEASE) { + if (!(peerContext->item.flags & RDP_PEER_ACTIVATED)) { + rdp_debug_verbose(peerContext->rdpBackend, " -> NOT ACTIVATED\n"); + return TRUE; + } + + /* Note: With FreeRDP 3.x, we seem to have KBD_FLAGS_RELEASE set when + * releasing a key and *NO* flag set when pressing... + */ + else if (flags & KBD_FLAGS_RELEASE) { keyState = WL_KEYBOARD_KEY_STATE_RELEASED; notify = 1; + } else if ((USE_FREERDP_VERSION >= 3) || flags & KBD_FLAGS_DOWN) { + keyState = WL_KEYBOARD_KEY_STATE_PRESSED; + notify = 1; } if (notify) { @@ -1531,8 +1554,8 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) /* Korean keyboard support: * WinPR's GetVirtualKeyCodeFromVirtualScanCode() can't handle hangul/hanja keys * hanja and hangeul keys are only present on Korean 103 keyboard (Type 8:SubType 6) */ - if (client->context->settings->KeyboardType == 8 && - client->context->settings->KeyboardSubType == 6 && + if (freerdp_settings_get_uint32(client->context->settings, FreeRDP_KeyboardType) == 8 && + freerdp_settings_get_uint32(client->context->settings, FreeRDP_KeyboardSubType) == 6 && ((full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANJA)) || (full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANGEUL)))) { if (full_code == (KBD_FLAGS_EXTENDED | ATKBD_RET_HANJA)) @@ -1552,7 +1575,10 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) } send_release_key = true; } else { - vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, client->context->settings->KeyboardType); + vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, + freerdp_settings_get_uint32(client->context->settings, + FreeRDP_KeyboardType)); + rdp_debug_verbose(peerContext->rdpBackend, " -> vk_code=0x%x\n", vk_code); } /* Korean keyboard support */ /* WinPR's GetKeycodeFromVirtualKeyCode() expects no extended bit for VK_HANGUL and VK_HANJA */ @@ -1560,7 +1586,7 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) if (flags & KBD_FLAGS_EXTENDED) vk_code |= KBDEXT; - scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV); + scan_code = GetKeycodeFromVirtualKeyCode(vk_code, WINPR_KEYCODE_TYPE_XKB); /*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0, vk_code, scan_code);*/ @@ -1617,14 +1643,21 @@ xf_peer_adjust_monitor_layout(freerdp_peer *client) unsigned int i; rdp_debug(b, "%s:\n", __func__); - rdp_debug(b, " DesktopWidth:%d, DesktopHeight:%d\n", settings->DesktopWidth, settings->DesktopHeight); - rdp_debug(b, " UseMultimon:%d\n", settings->UseMultimon); - rdp_debug(b, " ForceMultimon:%d\n", settings->ForceMultimon); - rdp_debug(b, " MonitorCount:%d\n", settings->MonitorCount); - rdp_debug(b, " HasMonitorAttributes:%d\n", settings->HasMonitorAttributes); - rdp_debug(b, " HiDefRemoteApp:%d\n", settings->HiDefRemoteApp); + rdp_debug(b, " DesktopWidth:%d, DesktopHeight:%d\n", + freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth), + freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)); + rdp_debug(b, " UseMultimon:%d\n", + freerdp_settings_get_bool(settings, FreeRDP_UseMultimon)); + rdp_debug(b, " ForceMultimon:%d\n", + freerdp_settings_get_bool(settings, FreeRDP_ForceMultimon)); + rdp_debug(b, " MonitorCount:%d\n", + freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount)); + rdp_debug(b, " HasMonitorAttributes:%d\n", + freerdp_settings_get_bool(settings, FreeRDP_HasMonitorAttributes)); + rdp_debug(b, " HiDefRemoteApp:%d\n", + freerdp_settings_get_bool(settings, FreeRDP_HiDefRemoteApp)); - if (settings->MonitorCount > 1) { + if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 1) { weston_log("multiple monitor is not supported"); fallback = true; } @@ -1632,18 +1665,19 @@ xf_peer_adjust_monitor_layout(freerdp_peer *client) if (!b->resizeable) fallback = true; - if (settings->MonitorCount > RDP_MAX_MONITOR) { + if (freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > RDP_MAX_MONITOR) { weston_log("Client reports more monitors then expected:(%d)\n", - settings->MonitorCount); + freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount)); return FALSE; } - if ((settings->MonitorCount > 0 && settings->MonitorDefArray) && !fallback) { - rdpMonitor *rdp_monitor = settings->MonitorDefArray; - monitor_count = settings->MonitorCount; + if ((freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount) > 0 && + freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray)) && !fallback) { + const rdpMonitor *rdp_monitor = freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray); + monitor_count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); monitors = xmalloc(sizeof(*monitors) * monitor_count); for (i = 0; i < monitor_count; i++) { monitors[i] = rdp_monitor[i]; - if (!settings->HasMonitorAttributes) { + if (!freerdp_settings_get_bool(settings, FreeRDP_HasMonitorAttributes)) { monitors[i].attributes.physicalWidth = 0; monitors[i].attributes.physicalHeight = 0; monitors[i].attributes.orientation = ORIENTATION_LANDSCAPE; @@ -1657,14 +1691,19 @@ xf_peer_adjust_monitor_layout(freerdp_peer *client) /* when no monitor array provided, generate from desktop settings */ monitors[0].x = 0; monitors[0].y = 0; - monitors[0].width = settings->DesktopWidth; - monitors[0].height = settings->DesktopHeight; + monitors[0].width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth); + monitors[0].height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight); monitors[0].is_primary = 1; - monitors[0].attributes.physicalWidth = settings->DesktopPhysicalWidth; - monitors[0].attributes.physicalHeight = settings->DesktopPhysicalHeight; - monitors[0].attributes.orientation = settings->DesktopOrientation; - monitors[0].attributes.desktopScaleFactor = settings->DesktopScaleFactor; - monitors[0].attributes.deviceScaleFactor = settings->DeviceScaleFactor; + monitors[0].attributes.physicalWidth = + freerdp_settings_get_uint32(settings, FreeRDP_DesktopPhysicalWidth); + monitors[0].attributes.physicalHeight = + freerdp_settings_get_uint32(settings, FreeRDP_DesktopPhysicalHeight); + monitors[0].attributes.orientation = + freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation); + monitors[0].attributes.desktopScaleFactor = + freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor); + monitors[0].attributes.deviceScaleFactor = + freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor); monitors[0].orig_screen = 0; if (!b->resizeable) { @@ -1703,7 +1742,30 @@ rdp_peer_init(freerdp_peer *client, struct rdp_backend *b) peerCtx->rdpBackend = b; settings = client->context->settings; +#if USE_FREERDP_VERSION >= 3 /* configure security settings */ + if (b->rdp_key) { + rdpPrivateKey* key = freerdp_key_new_from_file(b->rdp_key); + if (!key) + goto error_initialize; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1)) + goto error_initialize; + } + if (b->tls_enabled) { + rdpCertificate* cert = freerdp_certificate_new_from_file(b->server_cert); + if (!cert) + goto error_initialize; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1)) + goto error_initialize; + rdpPrivateKey* key = freerdp_key_new_from_file(b->server_key); + if (!key) + goto error_initialize; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1)) + goto error_initialize; + } else { + freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, FALSE); + } +#else if (b->rdp_key) settings->RdpKeyFile = strdup(b->rdp_key); if (b->tls_enabled) { @@ -1712,31 +1774,32 @@ rdp_peer_init(freerdp_peer *client, struct rdp_backend *b) } else { settings->TlsSecurity = FALSE; } - settings->NlaSecurity = FALSE; +#endif + freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE); if (!client->Initialize(client)) { weston_log("peer initialization failed\n"); goto error_initialize; } - settings->OsMajorType = OSMAJORTYPE_UNIX; - settings->OsMinorType = OSMINORTYPE_PSEUDO_XSERVER; - settings->ColorDepth = 32; - settings->RefreshRect = TRUE; - settings->RemoteFxCodec = b->remotefx_codec; - settings->NSCodec = TRUE; - settings->FrameMarkerCommandEnabled = TRUE; - settings->SurfaceFrameMarkerEnabled = TRUE; - settings->RedirectClipboard = TRUE; - settings->HasExtendedMouseEvent = TRUE; - settings->HasHorizontalWheel = TRUE; + freerdp_settings_set_uint32(settings, FreeRDP_OsMajorType, OSMAJORTYPE_UNIX); + freerdp_settings_set_uint32(settings, FreeRDP_OsMinorType, OSMINORTYPE_PSEUDO_XSERVER); + freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32); + freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, b->remotefx_codec); + freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel, TRUE); client->Capabilities = xf_peer_capabilities; client->PostConnect = xf_peer_post_connect; client->Activate = xf_peer_activate; if (b->resizeable) { - settings->SupportMonitorLayoutPdu = TRUE; + freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE); client->AdjustMonitorsLayout = xf_peer_adjust_monitor_layout; } @@ -1793,6 +1856,7 @@ error_dispatch_initialize: peerCtx->vcm = NULL; } + error_initialize: client->Close(client); return -1; diff --git a/libweston/backend-rdp/rdp.h b/libweston/backend-rdp/rdp.h index 818c316d..541579fe 100644 --- a/libweston/backend-rdp/rdp.h +++ b/libweston/backend-rdp/rdp.h @@ -27,6 +27,14 @@ #ifndef RDP_H #define RDP_H +/* Workaround an issue with clang and freerdp 3 headers. Another + * option would be to build with --std=c11 but weston itself isn't + * quite ready for that + */ +#if USE_FREERDP_VERSION >= 3 && defined(__clang__) +#pragma clang diagnostic ignored "-Wtypedef-redefinition" +#endif + #include #include @@ -44,6 +52,8 @@ #include #include +#include + #include "backend.h" #include "shared/helpers.h" @@ -68,6 +78,17 @@ #define ATKBD_RET_HANJA 0xf1 #define ATKBD_RET_HANGEUL 0xf2 +/* freerdp2 vs 3 compat */ +#if USE_FREERDP_VERSION >= 3 +#define FORM_DATA_RESP_COMM(r, f) (r).common.f +#define XF_KEV_CODE_TYPE UINT8 +#else +#define FORM_DATA_RESP_COMM(r, f) (r).f +#define WINPR_KBD_TYPE_JAPANESE KBD_TYPE_JAPANESE +#define WINPR_KEYCODE_TYPE_XKB KEYCODE_TYPE_EVDEV +#define XF_KEV_CODE_TYPE UINT16 +#endif + struct rdp_backend { struct weston_backend base; struct weston_compositor *compositor; diff --git a/libweston/backend-rdp/rdpclip.c b/libweston/backend-rdp/rdpclip.c index 27660efd..ce5708f4 100644 --- a/libweston/backend-rdp/rdpclip.c +++ b/libweston/backend-rdp/rdpclip.c @@ -37,6 +37,8 @@ #include "rdp.h" +#include + #include "libweston-internal.h" /* From MSDN, RegisterClipboardFormat API. @@ -194,10 +196,14 @@ clipboard_process_text_utf8(struct rdp_clipboard_data_source *source, bool is_se source->data_contents.size++; /* obtain size in UNICODE */ +#if USE_FREERDP_VERSION >= 3 + data_size = ConvertUtf8NToWChar(data, source->data_contents.size, NULL, 0); +#else data_size = MultiByteToWideChar(CP_UTF8, 0, data, source->data_contents.size, NULL, 0); +#endif if (data_size < 1) goto error_return; @@ -206,11 +212,18 @@ clipboard_process_text_utf8(struct rdp_clipboard_data_source *source, bool is_se goto error_return; /* convert to UNICODE */ +#if USE_FREERDP_VERSION >= 3 + data_size_in_char = ConvertUtf8NToWChar(data, + source->data_contents.size, + data_contents.data, + data_size); +#else data_size_in_char = MultiByteToWideChar(CP_UTF8, 0, data, source->data_contents.size, data_contents.data, data_size); +#endif assert(data_contents.size == (data_size_in_char * 2)); } else { /* Windows to Linux (UNICODE to utf-8) */ @@ -226,11 +239,17 @@ clipboard_process_text_utf8(struct rdp_clipboard_data_source *source, bool is_se goto error_return; /* obtain size in utf-8 */ +#if USE_FREERDP_VERSION >= 3 + data_size = ConvertWCharNToUtf8(source->data_contents.data, + data_size_in_char, + NULL, 0); +#else data_size = WideCharToMultiByte(CP_UTF8, 0, source->data_contents.data, data_size_in_char, NULL, 0, NULL, NULL); +#endif if (data_size < 1) goto error_return; @@ -238,12 +257,19 @@ clipboard_process_text_utf8(struct rdp_clipboard_data_source *source, bool is_se goto error_return; /* convert to utf-8 */ +#if USE_FREERDP_VERSION >= 3 + data_size = ConvertWCharNToUtf8(source->data_contents.data, + data_size_in_char, + data_contents.data, + data_size); +#else data_size = WideCharToMultiByte(CP_UTF8, 0, source->data_contents.data, data_size_in_char, data_contents.data, data_size, NULL, NULL); +#endif assert(data_contents.size == data_size); } @@ -721,9 +747,9 @@ clipboard_client_send_format_data_response(RdpPeerContext *ctx, struct rdp_clipb clipboard_supported_formats[source->format_index].mime_type, source->processed_data_size); - formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; - formatDataResponse.msgFlags = CB_RESPONSE_OK; - formatDataResponse.dataLen = source->processed_data_size; + FORM_DATA_RESP_COMM(formatDataResponse, msgType) = CB_FORMAT_DATA_RESPONSE; + FORM_DATA_RESP_COMM(formatDataResponse, msgFlags) = CB_RESPONSE_OK; + FORM_DATA_RESP_COMM(formatDataResponse, dataLen) = source->processed_data_size; formatDataResponse.requestedFormatData = source->processed_data_start; ctx->clipboard_server_context->ServerFormatDataResponse(ctx->clipboard_server_context, &formatDataResponse); /* if here failed to send response, what can we do ? */ @@ -745,9 +771,9 @@ clipboard_client_send_format_data_response_fail(RdpPeerContext *ctx, struct rdp_ source->data_response_fail_count++; } - formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; - formatDataResponse.msgFlags = CB_RESPONSE_FAIL; - formatDataResponse.dataLen = 0; + FORM_DATA_RESP_COMM(formatDataResponse, msgType) = CB_FORMAT_DATA_RESPONSE; + FORM_DATA_RESP_COMM(formatDataResponse, msgFlags) = CB_RESPONSE_FAIL; + FORM_DATA_RESP_COMM(formatDataResponse, dataLen) = 0; formatDataResponse.requestedFormatData = NULL; ctx->clipboard_server_context->ServerFormatDataResponse(ctx->clipboard_server_context, &formatDataResponse); /* if here failed to send response, what can we do ? */ @@ -1098,8 +1124,8 @@ clipboard_data_source_send(struct weston_data_source *base, /* update requesting format property */ source->format_index = index; /* request clipboard data from client */ - formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; - formatDataRequest.dataLen = 4; + FORM_DATA_RESP_COMM(formatDataRequest, msgType) = CB_FORMAT_DATA_REQUEST; + FORM_DATA_RESP_COMM(formatDataRequest, dataLen) = 4; formatDataRequest.requestedFormatId = source->client_format_id_table[index]; source->state = RDP_CLIPBOARD_SOURCE_REQUEST_DATA; rdp_debug_clipboard(b, "RDP %s (%p:%s) request data \"%s\" index:%d formatId:%d %s\n", @@ -1389,7 +1415,7 @@ clipboard_set_selection(struct wl_listener *listener, void *data) if (num_supported_format) { /* let client knows formats are available in server clipboard */ - formatList.msgType = CB_FORMAT_LIST; + FORM_DATA_RESP_COMM(formatList, msgType) = CB_FORMAT_LIST; formatList.numFormats = num_supported_format; formatList.formats = &format[0]; ctx->clipboard_server_context->ServerFormatList(ctx->clipboard_server_context, &formatList); @@ -1527,9 +1553,9 @@ clipboard_client_format_list(CliprdrServerContext *context, const CLIPRDR_FORMAT rdp_dispatch_task_to_display_loop(ctx, clipboard_data_source_publish, &source->task_base); fail: - formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; - formatListResponse.msgFlags = source ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; - formatListResponse.dataLen = 0; + FORM_DATA_RESP_COMM(formatListResponse, msgType) = CB_FORMAT_LIST_RESPONSE; + FORM_DATA_RESP_COMM(formatListResponse, msgFlags) = source ? CB_RESPONSE_OK : CB_RESPONSE_FAIL; + FORM_DATA_RESP_COMM(formatListResponse, dataLen) = 0; if (ctx->clipboard_server_context->ServerFormatListResponse(ctx->clipboard_server_context, &formatListResponse) != 0) { source->state = RDP_CLIPBOARD_SOURCE_FAILED; weston_log("Client: %s (%p:%s) ServerFormatListResponse failed\n", @@ -1555,8 +1581,8 @@ clipboard_client_format_data_response(CliprdrServerContext *context, const CLIPR rdp_debug_clipboard(b, "Client: %s (%p:%s) flags:%d dataLen:%d\n", __func__, source, clipboard_data_source_state_to_string(source), - formatDataResponse->msgFlags, - formatDataResponse->dataLen); + FORM_DATA_RESP_COMM(*formatDataResponse, msgFlags), + FORM_DATA_RESP_COMM(*formatDataResponse, dataLen)); assert_not_compositor_thread(b); @@ -1574,13 +1600,13 @@ clipboard_client_format_data_response(CliprdrServerContext *context, const CLIPR return -1; } - if (formatDataResponse->msgFlags == CB_RESPONSE_OK) { + if (FORM_DATA_RESP_COMM(*formatDataResponse, msgFlags) == CB_RESPONSE_OK) { /* Recieved data from client, cache to data source */ - if (wl_array_add(&source->data_contents, formatDataResponse->dataLen+1)) { + if (wl_array_add(&source->data_contents, FORM_DATA_RESP_COMM(*formatDataResponse, dataLen)+1)) { memcpy(source->data_contents.data, formatDataResponse->requestedFormatData, - formatDataResponse->dataLen); - source->data_contents.size = formatDataResponse->dataLen; + FORM_DATA_RESP_COMM(*formatDataResponse, dataLen)); + source->data_contents.size = FORM_DATA_RESP_COMM(*formatDataResponse, dataLen); /* regardless data type, make sure it ends with NULL */ ((char *)source->data_contents.data)[source->data_contents.size] = '\0'; /* data is ready, waiting to be written to destination */ @@ -1621,7 +1647,8 @@ clipboard_client_format_list_response(CliprdrServerContext *context, RdpPeerContext *ctx = (RdpPeerContext *)client->context; struct rdp_backend *b = ctx->rdpBackend; - rdp_debug_clipboard(b, "Client: %s msgFlags:0x%x\n", __func__, formatListResponse->msgFlags); + rdp_debug_clipboard(b, "Client: %s msgFlags:0x%x\n", __func__, + FORM_DATA_RESP_COMM(*formatListResponse, msgFlags)); assert_not_compositor_thread(b); return 0; }