Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
92
third_party/FreeRDP/client/SDL/SDL3/CMakeLists.txt
vendored
Normal file
92
third_party/FreeRDP/client/SDL/SDL3/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP SDL Client
|
||||
#
|
||||
# Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2024 Thincast Technologies GmbH
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
set(MODULE_NAME "sdl3-freerdp")
|
||||
|
||||
find_package(SDL3 REQUIRED)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_subdirectory(dialogs)
|
||||
set(SRCS
|
||||
sdl_types.hpp
|
||||
sdl_utils.cpp
|
||||
sdl_utils.hpp
|
||||
sdl_input.cpp
|
||||
sdl_input.hpp
|
||||
sdl_touch.cpp
|
||||
sdl_touch.hpp
|
||||
sdl_pointer.cpp
|
||||
sdl_pointer.hpp
|
||||
sdl_disp.cpp
|
||||
sdl_disp.hpp
|
||||
sdl_monitor.cpp
|
||||
sdl_monitor.hpp
|
||||
sdl_freerdp.hpp
|
||||
sdl_freerdp.cpp
|
||||
sdl_channels.hpp
|
||||
sdl_channels.cpp
|
||||
sdl_window.hpp
|
||||
sdl_window.cpp
|
||||
sdl_clip.hpp
|
||||
sdl_clip.cpp
|
||||
sdl_context.hpp
|
||||
sdl_context.cpp
|
||||
)
|
||||
|
||||
list(
|
||||
APPEND
|
||||
LIBS
|
||||
winpr
|
||||
freerdp
|
||||
freerdp-client
|
||||
Threads::Threads
|
||||
sdl3_client_res
|
||||
sdl3-dialogs
|
||||
sdl-common-aad-view
|
||||
sdl-common-prefs
|
||||
)
|
||||
|
||||
if(NOT WITH_SDL_LINK_SHARED)
|
||||
list(APPEND LIBS SDL3::SDL3-static)
|
||||
else()
|
||||
list(APPEND LIBS SDL3::SDL3)
|
||||
endif()
|
||||
set_target_properties(SDL3::Headers PROPERTIES SYSTEM TRUE)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
addtargetwithresourcefile(${MODULE_NAME} "${WIN32_GUI_FLAG}" "${PROJECT_VERSION}" SRCS)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS})
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/SDL")
|
||||
get_target_property(SDL_CLIENT_BINARY_NAME ${MODULE_NAME} OUTPUT_NAME)
|
||||
if(NOT WITH_CLIENT_SDL_VERSIONED)
|
||||
string(REPLACE "${MODULE_NAME}" "${PROJECT_NAME}" SDL_CLIENT_BINARY_NAME "${SDL_CLIENT_BINARY_NAME}")
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${SDL_CLIENT_BINARY_NAME})
|
||||
endif()
|
||||
|
||||
string(TIMESTAMP SDL_CLIENT_YEAR "%Y")
|
||||
set(SDL_CLIENT_UUID "com.freerdp.client.sdl3")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdl_config.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/sdl_config.hpp @ONLY)
|
||||
|
||||
installwithrpath(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client)
|
||||
install_freerdp_desktop("${MODULE_NAME}" "${SDL_CLIENT_UUID}")
|
||||
|
||||
add_subdirectory(man)
|
||||
87
third_party/FreeRDP/client/SDL/SDL3/dialogs/CMakeLists.txt
vendored
Normal file
87
third_party/FreeRDP/client/SDL/SDL3/dialogs/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP SDL Client
|
||||
#
|
||||
# Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2024 Thincast Technologies GmbH
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
set(SRCS
|
||||
sdl_button.hpp
|
||||
sdl_button.cpp
|
||||
sdl_buttons.hpp
|
||||
sdl_buttons.cpp
|
||||
sdl_dialogs.cpp
|
||||
sdl_dialogs.hpp
|
||||
sdl_widget.hpp
|
||||
sdl_widget.cpp
|
||||
sdl_widget_list.hpp
|
||||
sdl_widget_list.cpp
|
||||
sdl_input_widget.hpp
|
||||
sdl_input_widget.cpp
|
||||
sdl_input_widget_pair.hpp
|
||||
sdl_input_widget_pair.cpp
|
||||
sdl_input_widget_pair_list.hpp
|
||||
sdl_input_widget_pair_list.cpp
|
||||
sdl_select.hpp
|
||||
sdl_select.cpp
|
||||
sdl_select_list.hpp
|
||||
sdl_select_list.cpp
|
||||
sdl_selectable_widget.cpp
|
||||
sdl_selectable_widget.hpp
|
||||
sdl_connection_dialog.cpp
|
||||
sdl_connection_dialog.hpp
|
||||
sdl_connection_dialog_wrapper.cpp
|
||||
sdl_connection_dialog_wrapper.hpp
|
||||
sdl_blend_mode_guard.cpp
|
||||
sdl_blend_mode_guard.hpp
|
||||
)
|
||||
|
||||
list(APPEND LIBS sdl3_client_res winpr)
|
||||
|
||||
if(NOT WITH_SDL_LINK_SHARED)
|
||||
list(APPEND LIBS ${SDL3_STATIC_LIBRARIES})
|
||||
else()
|
||||
list(APPEND LIBS ${SDL3_LIBRARIES})
|
||||
endif()
|
||||
|
||||
macro(find_sdl_component name)
|
||||
find_package(${name} REQUIRED)
|
||||
if(WITH_SDL_LINK_SHARED)
|
||||
list(APPEND LIBS ${name}::${name})
|
||||
set_target_properties(${name}::${name}-shared PROPERTIES SYSTEM TRUE)
|
||||
else()
|
||||
list(APPEND LIBS ${name}::${name}-static)
|
||||
set_target_properties(${name}::${name}-static PROPERTIES SYSTEM TRUE)
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
find_sdl_component(SDL3_ttf)
|
||||
|
||||
option(WITH_SDL_IMAGE_DIALOGS "Build with SDL_image support (recommended)" OFF)
|
||||
if(WITH_SDL_IMAGE_DIALOGS)
|
||||
find_sdl_component(SDL3_image)
|
||||
add_compile_definitions(WITH_SDL_IMAGE_DIALOGS)
|
||||
endif()
|
||||
|
||||
add_subdirectory(res)
|
||||
|
||||
add_library(sdl3-dialogs STATIC ${SRCS} sdl_connection_dialog_hider.hpp sdl_connection_dialog_hider.cpp)
|
||||
|
||||
set_property(TARGET sdl3-dialogs PROPERTY FOLDER "Client/SDL")
|
||||
target_link_libraries(sdl3-dialogs PRIVATE ${LIBS})
|
||||
|
||||
option(SDL_DIALOG_TEST "Build dialog test binaries" OFF)
|
||||
if(SDL_DIALOG_TEST)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
93
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/OFL.txt
vendored
Normal file
93
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/OFL.txt
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/OpenSans-Italic-VariableFont_wdth,wght.ttf
vendored
Normal file
BIN
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/OpenSans-Italic-VariableFont_wdth,wght.ttf
vendored
Normal file
Binary file not shown.
BIN
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/OpenSans-VariableFont_wdth,wght.ttf
vendored
Normal file
BIN
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/OpenSans-VariableFont_wdth,wght.ttf
vendored
Normal file
Binary file not shown.
100
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/README.txt
vendored
Normal file
100
third_party/FreeRDP/client/SDL/SDL3/dialogs/font/README.txt
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
Open Sans Variable Font
|
||||
=======================
|
||||
|
||||
This download contains Open Sans as both variable fonts and static fonts.
|
||||
|
||||
Open Sans is a variable font with these axes:
|
||||
wdth
|
||||
wght
|
||||
|
||||
This means all the styles are contained in these files:
|
||||
OpenSans-VariableFont_wdth,wght.ttf
|
||||
OpenSans-Italic-VariableFont_wdth,wght.ttf
|
||||
|
||||
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||
in those cases you can use the static font files for Open Sans:
|
||||
static/OpenSans_Condensed-Light.ttf
|
||||
static/OpenSans_Condensed-Regular.ttf
|
||||
static/OpenSans_Condensed-Medium.ttf
|
||||
static/OpenSans_Condensed-SemiBold.ttf
|
||||
static/OpenSans_Condensed-Bold.ttf
|
||||
static/OpenSans_Condensed-ExtraBold.ttf
|
||||
static/OpenSans_SemiCondensed-Light.ttf
|
||||
static/OpenSans_SemiCondensed-Regular.ttf
|
||||
static/OpenSans_SemiCondensed-Medium.ttf
|
||||
static/OpenSans_SemiCondensed-SemiBold.ttf
|
||||
static/OpenSans_SemiCondensed-Bold.ttf
|
||||
static/OpenSans_SemiCondensed-ExtraBold.ttf
|
||||
static/OpenSans-Light.ttf
|
||||
static/OpenSans-Regular.ttf
|
||||
static/OpenSans-Medium.ttf
|
||||
static/OpenSans-SemiBold.ttf
|
||||
static/OpenSans-Bold.ttf
|
||||
static/OpenSans-ExtraBold.ttf
|
||||
static/OpenSans_Condensed-LightItalic.ttf
|
||||
static/OpenSans_Condensed-Italic.ttf
|
||||
static/OpenSans_Condensed-MediumItalic.ttf
|
||||
static/OpenSans_Condensed-SemiBoldItalic.ttf
|
||||
static/OpenSans_Condensed-BoldItalic.ttf
|
||||
static/OpenSans_Condensed-ExtraBoldItalic.ttf
|
||||
static/OpenSans_SemiCondensed-LightItalic.ttf
|
||||
static/OpenSans_SemiCondensed-Italic.ttf
|
||||
static/OpenSans_SemiCondensed-MediumItalic.ttf
|
||||
static/OpenSans_SemiCondensed-SemiBoldItalic.ttf
|
||||
static/OpenSans_SemiCondensed-BoldItalic.ttf
|
||||
static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf
|
||||
static/OpenSans-LightItalic.ttf
|
||||
static/OpenSans-Italic.ttf
|
||||
static/OpenSans-MediumItalic.ttf
|
||||
static/OpenSans-SemiBoldItalic.ttf
|
||||
static/OpenSans-BoldItalic.ttf
|
||||
static/OpenSans-ExtraBoldItalic.ttf
|
||||
|
||||
Get started
|
||||
-----------
|
||||
|
||||
1. Install the font files you want to use
|
||||
|
||||
2. Use your app's font picker to view the font family and all the
|
||||
available styles
|
||||
|
||||
Learn more about variable fonts
|
||||
-------------------------------
|
||||
|
||||
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||
https://variablefonts.typenetwork.com
|
||||
https://medium.com/variable-fonts
|
||||
|
||||
In desktop apps
|
||||
|
||||
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||
|
||||
Online
|
||||
|
||||
https://developers.google.com/fonts/docs/getting_started
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||
|
||||
Installing fonts
|
||||
|
||||
MacOS: https://support.apple.com/en-us/HT201749
|
||||
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||
|
||||
Android Apps
|
||||
|
||||
https://developers.google.com/fonts/docs/android
|
||||
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||
|
||||
License
|
||||
-------
|
||||
Please read the full license text (OFL.txt) to understand the permissions,
|
||||
restrictions and requirements for usage, redistribution, and modification.
|
||||
|
||||
You can use them in your products & projects – print or digital,
|
||||
commercial or otherwise.
|
||||
|
||||
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||
license for all details.
|
||||
31
third_party/FreeRDP/client/SDL/SDL3/dialogs/res/CMakeLists.txt
vendored
Normal file
31
third_party/FreeRDP/client/SDL/SDL3/dialogs/res/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP SDL Client
|
||||
#
|
||||
# Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2024 Thincast Technologies GmbH
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
set(SRCS sdl3_resource_manager.cpp sdl3_resource_manager.hpp)
|
||||
|
||||
add_library(sdl3_client_res STATIC ${SRCS})
|
||||
set_property(TARGET sdl3_client_res PROPERTY FOLDER "Client/SDL")
|
||||
|
||||
if(NOT WITH_SDL_LINK_SHARED)
|
||||
target_link_libraries(sdl3_client_res ${SDL3_STATIC_LIBRARIES})
|
||||
else()
|
||||
target_link_libraries(sdl3_client_res ${SDL3_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(sdl3_client_res sdl-common-client-res)
|
||||
|
||||
set_target_properties(sdl3_client_res PROPERTIES POSITION_INDEPENDENT_CODE ON INTERPROCEDURAL_OPTIMIZATION OFF)
|
||||
43
third_party/FreeRDP/client/SDL/SDL3/dialogs/res/sdl3_resource_manager.cpp
vendored
Normal file
43
third_party/FreeRDP/client/SDL/SDL3/dialogs/res/sdl3_resource_manager.cpp
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "sdl3_resource_manager.hpp"
|
||||
#include <iostream>
|
||||
#if __has_include(<filesystem>)
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#elif __has_include(<experimental/filesystem>)
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#else
|
||||
#error Could not find system header "<filesystem>" or "<experimental/filesystem>"
|
||||
#endif
|
||||
|
||||
SDL_IOStream* SDL3ResourceManager::get(const std::string& type, const std::string& id)
|
||||
{
|
||||
if (useCompiledResources())
|
||||
{
|
||||
auto d = data(type, id);
|
||||
if (!d)
|
||||
return nullptr;
|
||||
|
||||
return SDL_IOFromConstMem(d->data(), d->size());
|
||||
}
|
||||
|
||||
auto name = filename(type, id);
|
||||
return SDL_IOFromFile(name.c_str(), "rb");
|
||||
}
|
||||
38
third_party/FreeRDP/client/SDL/SDL3/dialogs/res/sdl3_resource_manager.hpp
vendored
Normal file
38
third_party/FreeRDP/client/SDL/SDL3/dialogs/res/sdl3_resource_manager.hpp
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <res/sdl_resource_manager.hpp>
|
||||
|
||||
class SDL3ResourceManager : public SDLResourceManager
|
||||
{
|
||||
public:
|
||||
SDL3ResourceManager() = delete;
|
||||
SDL3ResourceManager(const SDL3ResourceManager& other) = delete;
|
||||
SDL3ResourceManager(const SDL3ResourceManager&& other) = delete;
|
||||
~SDL3ResourceManager() = delete;
|
||||
SDL3ResourceManager& operator=(const SDL3ResourceManager& other) = delete;
|
||||
SDL3ResourceManager& operator=(SDL3ResourceManager&& other) = delete;
|
||||
|
||||
[[nodiscard]] static SDL_IOStream* get(const std::string& type, const std::string& id);
|
||||
};
|
||||
45
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_blend_mode_guard.cpp
vendored
Normal file
45
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_blend_mode_guard.cpp
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "sdl_blend_mode_guard.hpp"
|
||||
|
||||
SdlBlendModeGuard::SdlBlendModeGuard(const std::shared_ptr<SDL_Renderer>& renderer,
|
||||
SDL_BlendMode mode)
|
||||
: _renderer(renderer)
|
||||
{
|
||||
const auto rcb = SDL_GetRenderDrawBlendMode(_renderer.get(), &_restore_mode);
|
||||
if (!rcb)
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"[%s] SDL_GetRenderDrawBlendMode() failed with %s", __func__, SDL_GetError());
|
||||
else
|
||||
{
|
||||
const auto rbm = SDL_SetRenderDrawBlendMode(_renderer.get(), mode);
|
||||
if (!rbm)
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"[%s] SDL_SetRenderDrawBlendMode() failed with %s", __func__,
|
||||
SDL_GetError());
|
||||
else
|
||||
_current_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
bool SdlBlendModeGuard::update(SDL_BlendMode mode)
|
||||
{
|
||||
if (_current_mode != mode)
|
||||
{
|
||||
if (!SDL_SetRenderDrawBlendMode(_renderer.get(), mode))
|
||||
{
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"[%s] SDL_SetRenderDrawBlendMode() failed with %s", __func__,
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
_current_mode = mode;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SdlBlendModeGuard::~SdlBlendModeGuard()
|
||||
{
|
||||
const auto rbm = SDL_SetRenderDrawBlendMode(_renderer.get(), _restore_mode);
|
||||
if (!rbm)
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"[%s] SDL_SetRenderDrawBlendMode() failed with %s", __func__, SDL_GetError());
|
||||
}
|
||||
46
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_blend_mode_guard.hpp
vendored
Normal file
46
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_blend_mode_guard.hpp
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
class SdlBlendModeGuard
|
||||
{
|
||||
public:
|
||||
explicit SdlBlendModeGuard(const std::shared_ptr<SDL_Renderer>& renderer,
|
||||
SDL_BlendMode mode = SDL_BLENDMODE_NONE);
|
||||
~SdlBlendModeGuard();
|
||||
|
||||
SdlBlendModeGuard(SdlBlendModeGuard&& other) noexcept;
|
||||
SdlBlendModeGuard(const SdlBlendModeGuard& other) = delete;
|
||||
|
||||
SdlBlendModeGuard& operator=(const SdlBlendModeGuard& other) = delete;
|
||||
SdlBlendModeGuard& operator=(SdlBlendModeGuard&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool update(SDL_BlendMode mode);
|
||||
|
||||
private:
|
||||
SDL_BlendMode _restore_mode = SDL_BLENDMODE_INVALID;
|
||||
SDL_BlendMode _current_mode = SDL_BLENDMODE_INVALID;
|
||||
std::shared_ptr<SDL_Renderer> _renderer;
|
||||
};
|
||||
45
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_button.cpp
vendored
Normal file
45
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_button.cpp
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client Channels
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2023 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 <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "sdl_button.hpp"
|
||||
|
||||
SdlButton::SdlButton(std::shared_ptr<SDL_Renderer>& renderer, const std::string& label, int id,
|
||||
const SDL_FRect& rect)
|
||||
: SdlSelectableWidget(renderer, rect), _id(id)
|
||||
{
|
||||
_backgroundcolor = { 0x69, 0x66, 0x63, 0xff };
|
||||
_highlightcolor = { 0xcd, 0xca, 0x35, 0x60 };
|
||||
_mouseovercolor = { 0x66, 0xff, 0x66, 0x60 };
|
||||
_fontcolor = { 0xd1, 0xcf, 0xcd, 0xff };
|
||||
std::ignore = update_text(label);
|
||||
std::ignore = update();
|
||||
}
|
||||
|
||||
SdlButton::SdlButton(SdlButton&& other) noexcept = default;
|
||||
|
||||
SdlButton::~SdlButton() = default;
|
||||
|
||||
int SdlButton::id() const
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
24
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_button.hpp
vendored
Normal file
24
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_button.hpp
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "sdl_selectable_widget.hpp"
|
||||
|
||||
class SdlButton : public SdlSelectableWidget
|
||||
{
|
||||
public:
|
||||
SdlButton(std::shared_ptr<SDL_Renderer>& renderer, const std::string& label, int id,
|
||||
const SDL_FRect& rect);
|
||||
SdlButton(SdlButton&& other) noexcept;
|
||||
SdlButton(const SdlButton& other) = delete;
|
||||
~SdlButton() override;
|
||||
|
||||
SdlButton& operator=(const SdlButton& other) = delete;
|
||||
SdlButton& operator=(SdlButton&& other) = delete;
|
||||
|
||||
[[nodiscard]] int id() const;
|
||||
|
||||
private:
|
||||
int _id;
|
||||
};
|
||||
108
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_buttons.cpp
vendored
Normal file
108
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_buttons.cpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include "sdl_buttons.hpp"
|
||||
|
||||
static const Uint32 hpadding = 10;
|
||||
|
||||
SdlButtonList::~SdlButtonList() = default;
|
||||
|
||||
bool SdlButtonList::populate(std::shared_ptr<SDL_Renderer>& renderer,
|
||||
const std::vector<std::string>& labels, const std::vector<int>& ids,
|
||||
Sint32 total_width, Sint32 offsetY, Sint32 width, Sint32 height)
|
||||
{
|
||||
assert(renderer);
|
||||
assert(width >= 0);
|
||||
assert(height >= 0);
|
||||
assert(labels.size() == ids.size());
|
||||
|
||||
_list.clear();
|
||||
size_t button_width = ids.size() * (static_cast<size_t>(width) + hpadding) + hpadding;
|
||||
size_t offsetX = static_cast<size_t>(total_width) -
|
||||
std::min<size_t>(static_cast<size_t>(total_width), button_width);
|
||||
for (size_t x = 0; x < ids.size(); x++)
|
||||
{
|
||||
const size_t curOffsetX = offsetX + x * (static_cast<size_t>(width) + hpadding);
|
||||
const SDL_FRect rect = { static_cast<float>(curOffsetX), static_cast<float>(offsetY),
|
||||
static_cast<float>(width), static_cast<float>(height) };
|
||||
auto button = std::make_shared<SdlButton>(renderer, labels.at(x), ids.at(x), rect);
|
||||
_list.emplace_back(button);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<SdlButton> SdlButtonList::get_selected(const SDL_MouseButtonEvent& button)
|
||||
{
|
||||
const auto x = button.x;
|
||||
const auto y = button.y;
|
||||
|
||||
return get_selected(x, y);
|
||||
}
|
||||
|
||||
std::shared_ptr<SdlButton> SdlButtonList::get_selected(float x, float y)
|
||||
{
|
||||
for (auto& btn : _list)
|
||||
{
|
||||
auto r = btn->rect();
|
||||
if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
|
||||
return btn;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SdlButtonList::set_highlight_next(bool reset)
|
||||
{
|
||||
if (reset)
|
||||
_highlighted = nullptr;
|
||||
else
|
||||
{
|
||||
auto next = _highlight_index++;
|
||||
_highlight_index %= _list.size();
|
||||
auto& element = _list.at(next);
|
||||
_highlighted = element;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlButtonList::set_highlight(size_t index)
|
||||
{
|
||||
if (index >= _list.size())
|
||||
{
|
||||
_highlighted = nullptr;
|
||||
return false;
|
||||
}
|
||||
auto& element = _list.at(index);
|
||||
_highlighted = element;
|
||||
_highlight_index = ++index % _list.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlButtonList::set_mouseover(float x, float y)
|
||||
{
|
||||
_mouseover = get_selected(x, y);
|
||||
return _mouseover != nullptr;
|
||||
}
|
||||
|
||||
void SdlButtonList::clear()
|
||||
{
|
||||
_list.clear();
|
||||
_mouseover = nullptr;
|
||||
_highlighted = nullptr;
|
||||
_highlight_index = 0;
|
||||
}
|
||||
|
||||
bool SdlButtonList::update()
|
||||
{
|
||||
for (auto& btn : _list)
|
||||
{
|
||||
if (!btn->highlight(btn == _highlighted))
|
||||
return false;
|
||||
if (!btn->mouseover(btn == _mouseover))
|
||||
return false;
|
||||
|
||||
if (!btn->update())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
39
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_buttons.hpp
vendored
Normal file
39
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_buttons.hpp
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "sdl_button.hpp"
|
||||
|
||||
class SdlButtonList
|
||||
{
|
||||
public:
|
||||
SdlButtonList() = default;
|
||||
SdlButtonList(const SdlButtonList& other) = delete;
|
||||
SdlButtonList(SdlButtonList&& other) = delete;
|
||||
virtual ~SdlButtonList();
|
||||
|
||||
SdlButtonList& operator=(const SdlButtonList& other) = delete;
|
||||
SdlButtonList& operator=(SdlButtonList&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool populate(std::shared_ptr<SDL_Renderer>& renderer,
|
||||
const std::vector<std::string>& labels, const std::vector<int>& ids,
|
||||
Sint32 total_width, Sint32 offsetY, Sint32 width, Sint32 height);
|
||||
|
||||
[[nodiscard]] bool update();
|
||||
[[nodiscard]] std::shared_ptr<SdlButton> get_selected(const SDL_MouseButtonEvent& button);
|
||||
[[nodiscard]] std::shared_ptr<SdlButton> get_selected(float x, float y);
|
||||
|
||||
bool set_highlight_next(bool reset = false);
|
||||
bool set_highlight(size_t index);
|
||||
bool set_mouseover(float x, float y);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<SdlButton>> _list;
|
||||
std::shared_ptr<SdlButton> _highlighted = nullptr;
|
||||
size_t _highlight_index = 0;
|
||||
std::shared_ptr<SdlButton> _mouseover = nullptr;
|
||||
};
|
||||
479
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog.cpp
vendored
Normal file
479
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog.cpp
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <thread>
|
||||
|
||||
#include "sdl_connection_dialog.hpp"
|
||||
#include "../sdl_utils.hpp"
|
||||
#include "../sdl_context.hpp"
|
||||
#include "res/sdl3_resource_manager.hpp"
|
||||
|
||||
static const SDL_Color textcolor = { 0xd1, 0xcf, 0xcd, 0xff };
|
||||
static const SDL_Color infocolor = { 0x43, 0xe0, 0x0f, 0x60 };
|
||||
static const SDL_Color warncolor = { 0xcd, 0xca, 0x35, 0x60 };
|
||||
static const SDL_Color errorcolor = { 0xf7, 0x22, 0x30, 0x60 };
|
||||
|
||||
static const Uint32 vpadding = 5;
|
||||
static const Uint32 hpadding = 5;
|
||||
|
||||
SDLConnectionDialog::SDLConnectionDialog(rdpContext* context) : _context(context)
|
||||
{
|
||||
std::ignore = hide();
|
||||
}
|
||||
|
||||
SDLConnectionDialog::~SDLConnectionDialog()
|
||||
{
|
||||
resetTimer();
|
||||
destroyWindow();
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::setTitle(const char* fmt, ...)
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
_title = print(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return show(SdlConnectionDialogWrapper::MSG_NONE);
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::showInfo(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
auto rc = show(SdlConnectionDialogWrapper::MSG_INFO, fmt, ap);
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::showWarn(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
auto rc = show(SdlConnectionDialogWrapper::MSG_WARN, fmt, ap);
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::showError(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
auto rc = show(SdlConnectionDialogWrapper::MSG_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
if (!rc)
|
||||
return rc;
|
||||
return setTimer();
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::show()
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
return show(_type_active);
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::hide()
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
return show(SdlConnectionDialogWrapper::MSG_DISCARD);
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::running() const
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
return _running;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::updateMsg(SdlConnectionDialogWrapper::MsgType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SdlConnectionDialogWrapper::MSG_INFO:
|
||||
case SdlConnectionDialogWrapper::MSG_WARN:
|
||||
case SdlConnectionDialogWrapper::MSG_ERROR:
|
||||
_type_active = type;
|
||||
if (!createWindow())
|
||||
return false;
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_DISCARD:
|
||||
resetTimer();
|
||||
destroyWindow();
|
||||
break;
|
||||
default:
|
||||
if (_window)
|
||||
{
|
||||
SDL_SetWindowTitle(_window.get(), _title.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::setModal()
|
||||
{
|
||||
if (_window)
|
||||
{
|
||||
auto sdl = get_context(_context);
|
||||
auto parent = sdl->getFirstWindow();
|
||||
if (!parent)
|
||||
return true;
|
||||
|
||||
if (!SDL_SetWindowParent(_window.get(), parent->window()))
|
||||
return false;
|
||||
if (!SDL_SetWindowModal(_window.get(), true))
|
||||
return false;
|
||||
if (!SDL_RaiseWindow(_window.get()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::updateInternal()
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
for (auto& btn : _list)
|
||||
{
|
||||
if (!btn.widget.update_text(_msg))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::wait(bool ignoreRdpContext)
|
||||
{
|
||||
while (running())
|
||||
{
|
||||
if (!ignoreRdpContext)
|
||||
{
|
||||
if (freerdp_shall_disconnect_context(_context))
|
||||
return false;
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::handle(const SDL_Event& event)
|
||||
{
|
||||
Uint32 windowID = 0;
|
||||
if (_window)
|
||||
{
|
||||
windowID = SDL_GetWindowID(_window.get());
|
||||
}
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_USER_RETRY_DIALOG:
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
auto type = static_cast<SdlConnectionDialogWrapper::MsgType>(event.user.code);
|
||||
return updateMsg(type);
|
||||
}
|
||||
case SDL_EVENT_QUIT:
|
||||
resetTimer();
|
||||
destroyWindow();
|
||||
return false;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
if (visible())
|
||||
{
|
||||
auto& ev = reinterpret_cast<const SDL_KeyboardEvent&>(event);
|
||||
if (!update())
|
||||
return false;
|
||||
switch (event.key.key)
|
||||
{
|
||||
case SDLK_RETURN:
|
||||
case SDLK_RETURN2:
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_KP_ENTER:
|
||||
if (event.type == SDL_EVENT_KEY_UP)
|
||||
{
|
||||
freerdp_abort_connect_context(_context);
|
||||
std::ignore = sdl_push_quit();
|
||||
}
|
||||
break;
|
||||
case SDLK_TAB:
|
||||
if (!_buttons.set_highlight_next())
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return windowID == ev.windowID;
|
||||
}
|
||||
return false;
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
if (visible())
|
||||
{
|
||||
auto& ev = reinterpret_cast<const SDL_MouseMotionEvent&>(event);
|
||||
|
||||
_buttons.set_mouseover(event.button.x, event.button.y);
|
||||
if (!update())
|
||||
return false;
|
||||
return windowID == ev.windowID;
|
||||
}
|
||||
return false;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
if (visible())
|
||||
{
|
||||
auto& ev = reinterpret_cast<const SDL_MouseButtonEvent&>(event);
|
||||
if (!update())
|
||||
return false;
|
||||
|
||||
auto button = _buttons.get_selected(event.button);
|
||||
if (button)
|
||||
{
|
||||
if (event.type == SDL_EVENT_MOUSE_BUTTON_UP)
|
||||
{
|
||||
freerdp_abort_connect_context(_context);
|
||||
std::ignore = sdl_push_quit();
|
||||
}
|
||||
}
|
||||
|
||||
return windowID == ev.windowID;
|
||||
}
|
||||
return false;
|
||||
case SDL_EVENT_MOUSE_WHEEL:
|
||||
if (visible())
|
||||
{
|
||||
auto& ev = reinterpret_cast<const SDL_MouseWheelEvent&>(event);
|
||||
if (!update())
|
||||
return false;
|
||||
return windowID == ev.windowID;
|
||||
}
|
||||
return false;
|
||||
case SDL_EVENT_FINGER_UP:
|
||||
case SDL_EVENT_FINGER_DOWN:
|
||||
if (visible())
|
||||
{
|
||||
auto& ev = reinterpret_cast<const SDL_TouchFingerEvent&>(event);
|
||||
if (!update())
|
||||
return false;
|
||||
return windowID == ev.windowID;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
if ((event.type >= SDL_EVENT_WINDOW_FIRST) && (event.type <= SDL_EVENT_WINDOW_LAST))
|
||||
{
|
||||
auto& ev = reinterpret_cast<const SDL_WindowEvent&>(event);
|
||||
switch (ev.type)
|
||||
{
|
||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||
if (windowID == ev.windowID)
|
||||
{
|
||||
freerdp_abort_connect_context(_context);
|
||||
std::ignore = sdl_push_quit();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!update())
|
||||
return false;
|
||||
if (!setModal())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return windowID == ev.windowID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::visible() const
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
return SdlWidgetList::visible();
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::createWindow()
|
||||
{
|
||||
destroyWindow();
|
||||
|
||||
const size_t widget_height = 50;
|
||||
const size_t widget_width = 600;
|
||||
const size_t total_height = 300;
|
||||
|
||||
if (!reset(_title, widget_width, total_height))
|
||||
return false;
|
||||
|
||||
if (!setModal())
|
||||
return false;
|
||||
|
||||
SDL_Color res_bgcolor;
|
||||
switch (_type_active)
|
||||
{
|
||||
case SdlConnectionDialogWrapper::MSG_INFO:
|
||||
res_bgcolor = infocolor;
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_WARN:
|
||||
res_bgcolor = warncolor;
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_ERROR:
|
||||
res_bgcolor = errorcolor;
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_DISCARD:
|
||||
default:
|
||||
res_bgcolor = _backgroundcolor;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
std::string res_name;
|
||||
switch (_type_active)
|
||||
{
|
||||
case SdlConnectionDialogWrapper::MSG_INFO:
|
||||
res_name = "icon_info.svg";
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_WARN:
|
||||
res_name = "icon_warning.svg";
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_ERROR:
|
||||
res_name = "icon_error.svg";
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_DISCARD:
|
||||
default:
|
||||
res_name = "";
|
||||
break;
|
||||
}
|
||||
|
||||
const auto height = (total_height - 3.0f * vpadding) / 2.0f;
|
||||
SDL_FRect iconRect{ hpadding, vpadding, widget_width / 4.0f - 2.0f * hpadding, height };
|
||||
widget_cfg_t icon{ textcolor,
|
||||
res_bgcolor,
|
||||
{ _renderer, iconRect,
|
||||
SDL3ResourceManager::get(SDLResourceManager::typeImages(), res_name) } };
|
||||
_list.emplace_back(std::move(icon));
|
||||
|
||||
iconRect.y += height;
|
||||
|
||||
widget_cfg_t logo{ textcolor,
|
||||
_backgroundcolor,
|
||||
{ _renderer, iconRect,
|
||||
SDL3ResourceManager::get(SDLResourceManager::typeImages(),
|
||||
"FreeRDP_Icon.svg") } };
|
||||
_list.emplace_back(std::move(logo));
|
||||
|
||||
SDL_FRect rect = { widget_width / 4.0f, vpadding, widget_width * 3.0f / 4.0f,
|
||||
total_height - 3ul * vpadding - widget_height };
|
||||
#else
|
||||
SDL_FRect rect = { hpadding, vpadding, widget_width - 2ul * hpadding,
|
||||
total_height - 2ul * vpadding };
|
||||
#endif
|
||||
|
||||
widget_cfg_t w{ textcolor, _backgroundcolor, { _renderer, rect } };
|
||||
if (!w.widget.set_wrap(true, widget_width))
|
||||
return false;
|
||||
_list.emplace_back(std::move(w));
|
||||
rect.y += widget_height + vpadding;
|
||||
|
||||
const std::vector<int> buttonids = { 1 };
|
||||
const std::vector<std::string> buttonlabels = { "cancel" };
|
||||
if (!_buttons.populate(_renderer, buttonlabels, buttonids, widget_width,
|
||||
total_height - widget_height - vpadding,
|
||||
static_cast<Sint32>(widget_width / 2),
|
||||
static_cast<Sint32>(widget_height)))
|
||||
return false;
|
||||
if (!_buttons.set_highlight(0))
|
||||
return false;
|
||||
|
||||
if (!SDL_ShowWindow(_window.get()))
|
||||
return false;
|
||||
if (!SDL_RaiseWindow(_window.get()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLConnectionDialog::destroyWindow()
|
||||
{
|
||||
_buttons.clear();
|
||||
_list.clear();
|
||||
_renderer = nullptr;
|
||||
_window = nullptr;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::show(SdlConnectionDialogWrapper::MsgType type, const char* fmt,
|
||||
va_list ap)
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
_msg = print(fmt, ap);
|
||||
return show(type);
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::show(SdlConnectionDialogWrapper::MsgType type)
|
||||
{
|
||||
if (SDL_IsMainThread())
|
||||
return updateMsg(type);
|
||||
else
|
||||
return sdl_push_user_event(SDL_EVENT_USER_RETRY_DIALOG, type);
|
||||
}
|
||||
|
||||
std::string SDLConnectionDialog::print(const char* fmt, va_list ap)
|
||||
{
|
||||
int size = -1;
|
||||
std::string res;
|
||||
|
||||
do
|
||||
{
|
||||
res.resize(128);
|
||||
if (size > 0)
|
||||
res.resize(WINPR_ASSERTING_INT_CAST(uint32_t, size));
|
||||
|
||||
va_list copy = {};
|
||||
va_copy(copy, ap);
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
|
||||
size = vsnprintf(res.data(), res.size(), fmt, copy);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
va_end(copy);
|
||||
|
||||
} while ((size > 0) && (static_cast<size_t>(size) > res.size()));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SDLConnectionDialog::setTimer(Uint32 timeoutMS)
|
||||
{
|
||||
std::scoped_lock lock(_mux);
|
||||
resetTimer();
|
||||
|
||||
_timer = SDL_AddTimer(timeoutMS, &SDLConnectionDialog::timeout, this);
|
||||
_running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLConnectionDialog::resetTimer()
|
||||
{
|
||||
if (_running)
|
||||
SDL_RemoveTimer(_timer);
|
||||
_running = false;
|
||||
}
|
||||
|
||||
Uint32 SDLConnectionDialog::timeout(void* pvthis, [[maybe_unused]] SDL_TimerID timerID,
|
||||
[[maybe_unused]] Uint32 intervalMS)
|
||||
{
|
||||
auto self = static_cast<SDLConnectionDialog*>(pvthis);
|
||||
std::ignore = self->hide();
|
||||
self->_running = false;
|
||||
return 0;
|
||||
}
|
||||
95
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog.hpp
vendored
Normal file
95
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog.hpp
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_buttons.hpp"
|
||||
#include "sdl_connection_dialog_wrapper.hpp"
|
||||
#include "sdl_widget.hpp"
|
||||
#include "sdl_widget_list.hpp"
|
||||
|
||||
class SDLConnectionDialog : public SdlWidgetList
|
||||
{
|
||||
public:
|
||||
explicit SDLConnectionDialog(rdpContext* context);
|
||||
SDLConnectionDialog(const SDLConnectionDialog& other) = delete;
|
||||
SDLConnectionDialog(const SDLConnectionDialog&& other) = delete;
|
||||
~SDLConnectionDialog() override;
|
||||
|
||||
SDLConnectionDialog& operator=(const SDLConnectionDialog& other) = delete;
|
||||
SDLConnectionDialog& operator=(SDLConnectionDialog&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool setTitle(const char* fmt, ...);
|
||||
[[nodiscard]] bool showInfo(const char* fmt, ...);
|
||||
[[nodiscard]] bool showWarn(const char* fmt, ...);
|
||||
[[nodiscard]] bool showError(const char* fmt, ...);
|
||||
|
||||
[[nodiscard]] bool show();
|
||||
[[nodiscard]] bool hide();
|
||||
|
||||
[[nodiscard]] bool running() const;
|
||||
[[nodiscard]] bool wait(bool ignoreRdpContextQuit = false);
|
||||
|
||||
[[nodiscard]] bool handle(const SDL_Event& event);
|
||||
|
||||
[[nodiscard]] bool visible() const override;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool updateInternal() override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool createWindow();
|
||||
void destroyWindow();
|
||||
|
||||
[[nodiscard]] bool updateMsg(SdlConnectionDialogWrapper::MsgType type);
|
||||
|
||||
[[nodiscard]] bool setModal();
|
||||
|
||||
[[nodiscard]] bool show(SdlConnectionDialogWrapper::MsgType type, const char* fmt, va_list ap);
|
||||
[[nodiscard]] bool show(SdlConnectionDialogWrapper::MsgType type);
|
||||
|
||||
[[nodiscard]] static std::string print(const char* fmt, va_list ap);
|
||||
[[nodiscard]] bool setTimer(Uint32 timeoutMS = 15000);
|
||||
void resetTimer();
|
||||
|
||||
[[nodiscard]] static Uint32 timeout(void* pvthis, SDL_TimerID timerID, Uint32 intervalMS);
|
||||
|
||||
struct widget_cfg_t
|
||||
{
|
||||
SDL_Color fgcolor = {};
|
||||
SDL_Color bgcolor = {};
|
||||
SdlWidget widget;
|
||||
};
|
||||
|
||||
rdpContext* _context = nullptr;
|
||||
mutable std::mutex _mux;
|
||||
std::string _title;
|
||||
std::string _msg;
|
||||
SdlConnectionDialogWrapper::MsgType _type_active = SdlConnectionDialogWrapper::MSG_NONE;
|
||||
SDL_TimerID _timer = 0;
|
||||
bool _running = false;
|
||||
std::vector<widget_cfg_t> _list;
|
||||
};
|
||||
13
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_hider.cpp
vendored
Normal file
13
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_hider.cpp
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "sdl_connection_dialog_hider.hpp"
|
||||
#include "../sdl_context.hpp"
|
||||
|
||||
SDLConnectionDialogHider::SDLConnectionDialogHider(SdlContext* sdl)
|
||||
: _sdl(sdl), _visible(_sdl->getDialog().isVisible())
|
||||
{
|
||||
_sdl->getDialog().show(false);
|
||||
}
|
||||
|
||||
SDLConnectionDialogHider::~SDLConnectionDialogHider()
|
||||
{
|
||||
_sdl->getDialog().show(_visible);
|
||||
}
|
||||
39
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_hider.hpp
vendored
Normal file
39
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_hider.hpp
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../sdl_types.hpp"
|
||||
|
||||
class SDLConnectionDialogHider
|
||||
{
|
||||
public:
|
||||
explicit SDLConnectionDialogHider(SdlContext* sdl);
|
||||
|
||||
SDLConnectionDialogHider(const SDLConnectionDialogHider& other) = delete;
|
||||
SDLConnectionDialogHider(SDLConnectionDialogHider&& other) = delete;
|
||||
SDLConnectionDialogHider& operator=(const SDLConnectionDialogHider& other) = delete;
|
||||
SDLConnectionDialogHider& operator=(SDLConnectionDialogHider&& other) = delete;
|
||||
|
||||
~SDLConnectionDialogHider();
|
||||
|
||||
private:
|
||||
SdlContext* _sdl = nullptr;
|
||||
bool _visible = false;
|
||||
};
|
||||
287
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_wrapper.cpp
vendored
Normal file
287
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_wrapper.cpp
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "../sdl_utils.hpp"
|
||||
#include "sdl_connection_dialog.hpp"
|
||||
#include "sdl_connection_dialog_wrapper.hpp"
|
||||
|
||||
SdlConnectionDialogWrapper::SdlConnectionDialogWrapper(wLog* log) : _log(log)
|
||||
{
|
||||
}
|
||||
|
||||
SdlConnectionDialogWrapper::~SdlConnectionDialogWrapper() = default;
|
||||
|
||||
void SdlConnectionDialogWrapper::create(rdpContext* context)
|
||||
{
|
||||
const auto enabled =
|
||||
freerdp_settings_get_bool(context->settings, FreeRDP_UseCommonStdioCallbacks);
|
||||
_connection_dialog.reset();
|
||||
if (!enabled)
|
||||
_connection_dialog = std::make_unique<SDLConnectionDialog>(context);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::destroy()
|
||||
{
|
||||
_connection_dialog.reset();
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::isRunning() const
|
||||
{
|
||||
std::unique_lock lock(_mux);
|
||||
if (!_connection_dialog)
|
||||
return false;
|
||||
return _connection_dialog->running();
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::isVisible() const
|
||||
{
|
||||
std::unique_lock lock(_mux);
|
||||
if (!_connection_dialog)
|
||||
return false;
|
||||
return _connection_dialog->visible();
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::handleEvent(const SDL_Event& event)
|
||||
{
|
||||
std::unique_lock lock(_mux);
|
||||
if (!_connection_dialog)
|
||||
return false;
|
||||
return _connection_dialog->handle(event);
|
||||
}
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(1, 0)
|
||||
static std::string format(WINPR_FORMAT_ARG const char* fmt, va_list ap)
|
||||
{
|
||||
va_list ap1 = {};
|
||||
va_copy(ap1, ap);
|
||||
const int size = vsnprintf(nullptr, 0, fmt, ap1);
|
||||
va_end(ap1);
|
||||
|
||||
if (size < 0)
|
||||
return "";
|
||||
|
||||
std::string msg;
|
||||
msg.resize(static_cast<size_t>(size) + 1);
|
||||
|
||||
va_list ap2 = {};
|
||||
va_copy(ap2, ap);
|
||||
std::ignore = vsnprintf(msg.data(), msg.size(), fmt, ap2);
|
||||
va_end(ap2);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::setTitle(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
setTitle(format(fmt, ap));
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::setTitle(const std::string& title)
|
||||
{
|
||||
push(EventArg{ title });
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::showInfo(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
showInfo(format(fmt, ap));
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::showInfo(const std::string& info)
|
||||
{
|
||||
show(MSG_INFO, info);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::showWarn(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
showWarn(format(fmt, ap));
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::showWarn(const std::string& info)
|
||||
{
|
||||
show(MSG_WARN, info);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::showError(const char* fmt, ...)
|
||||
{
|
||||
va_list ap = {};
|
||||
va_start(ap, fmt);
|
||||
showError(format(fmt, ap));
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::showError(const std::string& error)
|
||||
{
|
||||
show(MSG_ERROR, error);
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::show(SdlConnectionDialogWrapper::MsgType type,
|
||||
const std::string& msg)
|
||||
{
|
||||
push({ type, msg, true });
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::show(bool visible)
|
||||
{
|
||||
push(EventArg{ visible });
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::handleShow()
|
||||
{
|
||||
std::unique_lock lock(_mux);
|
||||
while (!_queue.empty())
|
||||
{
|
||||
auto arg = _queue.front();
|
||||
_queue.pop();
|
||||
|
||||
if (arg.hasTitle() && _connection_dialog)
|
||||
{
|
||||
std::ignore = _connection_dialog->setTitle(arg.title().c_str());
|
||||
}
|
||||
|
||||
if (arg.hasType() && arg.hasMessage())
|
||||
{
|
||||
switch (arg.type())
|
||||
{
|
||||
case SdlConnectionDialogWrapper::MSG_INFO:
|
||||
if (_connection_dialog)
|
||||
std::ignore = _connection_dialog->showInfo(arg.message().c_str());
|
||||
else
|
||||
WLog_Print(_log, WLOG_INFO, "%s", arg.message().c_str());
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_WARN:
|
||||
if (_connection_dialog)
|
||||
std::ignore = _connection_dialog->showWarn(arg.message().c_str());
|
||||
else
|
||||
WLog_Print(_log, WLOG_WARN, "%s", arg.message().c_str());
|
||||
break;
|
||||
case SdlConnectionDialogWrapper::MSG_ERROR:
|
||||
if (_connection_dialog)
|
||||
std::ignore = _connection_dialog->showError(arg.message().c_str());
|
||||
else
|
||||
WLog_Print(_log, WLOG_ERROR, "%s", arg.message().c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.hasVisibility() && _connection_dialog)
|
||||
{
|
||||
if (arg.visible())
|
||||
std::ignore = _connection_dialog->show();
|
||||
else
|
||||
std::ignore = _connection_dialog->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConnectionDialogWrapper::push(EventArg&& arg)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(_mux);
|
||||
_queue.push(std::move(arg));
|
||||
}
|
||||
|
||||
auto rc = SDL_RunOnMainThread(
|
||||
[](void* user)
|
||||
{
|
||||
auto dlg = static_cast<SdlConnectionDialogWrapper*>(user);
|
||||
dlg->handleShow();
|
||||
},
|
||||
this, false);
|
||||
if (!rc)
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] SDL_RunOnMainThread failed with %s",
|
||||
__func__, SDL_GetError());
|
||||
}
|
||||
|
||||
SdlConnectionDialogWrapper::EventArg::EventArg(bool visible) : _visible(visible), _mask(8)
|
||||
{
|
||||
}
|
||||
|
||||
SdlConnectionDialogWrapper::EventArg::EventArg(const std::string& title) : _title(title), _mask(1)
|
||||
{
|
||||
}
|
||||
|
||||
SdlConnectionDialogWrapper::EventArg::EventArg(MsgType type, const std::string& msg, bool visible)
|
||||
: _message(msg), _type(type), _visible(visible), _mask(14)
|
||||
{
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::EventArg::hasTitle() const
|
||||
{
|
||||
return _mask & 0x01;
|
||||
}
|
||||
|
||||
const std::string& SdlConnectionDialogWrapper::EventArg::title() const
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::EventArg::hasMessage() const
|
||||
{
|
||||
return _mask & 0x02;
|
||||
}
|
||||
|
||||
const std::string& SdlConnectionDialogWrapper::EventArg::message() const
|
||||
{
|
||||
return _message;
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::EventArg::hasType() const
|
||||
{
|
||||
return _mask & 0x04;
|
||||
}
|
||||
|
||||
SdlConnectionDialogWrapper::MsgType SdlConnectionDialogWrapper::EventArg::type() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::EventArg::hasVisibility() const
|
||||
{
|
||||
return _mask & 0x08;
|
||||
}
|
||||
|
||||
bool SdlConnectionDialogWrapper::EventArg::visible() const
|
||||
{
|
||||
return _visible;
|
||||
}
|
||||
|
||||
std::string SdlConnectionDialogWrapper::EventArg::str() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ title:" << _title << ", message:" << _message << ", type:" << _type
|
||||
<< ", visible:" << _visible << ", mask:" << _mask << "}";
|
||||
return ss.str();
|
||||
}
|
||||
122
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_wrapper.hpp
vendored
Normal file
122
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_connection_dialog_wrapper.hpp
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/platform.h>
|
||||
#include <freerdp/types.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
class SDLConnectionDialog;
|
||||
|
||||
class SdlConnectionDialogWrapper
|
||||
{
|
||||
public:
|
||||
enum MsgType
|
||||
{
|
||||
MSG_NONE,
|
||||
MSG_INFO,
|
||||
MSG_WARN,
|
||||
MSG_ERROR,
|
||||
MSG_DISCARD
|
||||
};
|
||||
|
||||
explicit SdlConnectionDialogWrapper(wLog* log);
|
||||
~SdlConnectionDialogWrapper();
|
||||
|
||||
SdlConnectionDialogWrapper(const SdlConnectionDialogWrapper& other) = delete;
|
||||
SdlConnectionDialogWrapper(SdlConnectionDialogWrapper&& other) = delete;
|
||||
|
||||
SdlConnectionDialogWrapper& operator=(const SdlConnectionDialogWrapper& other) = delete;
|
||||
SdlConnectionDialogWrapper& operator=(SdlConnectionDialogWrapper&& other) = delete;
|
||||
|
||||
void create(rdpContext* context);
|
||||
void destroy();
|
||||
|
||||
[[nodiscard]] bool isRunning() const;
|
||||
[[nodiscard]] bool isVisible() const;
|
||||
|
||||
[[nodiscard]] bool handleEvent(const SDL_Event& event);
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(2, 3)
|
||||
void setTitle(WINPR_FORMAT_ARG const char* fmt, ...);
|
||||
void setTitle(const std::string& title);
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(2, 3)
|
||||
void showInfo(WINPR_FORMAT_ARG const char* fmt, ...);
|
||||
void showInfo(const std::string& info);
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(2, 3)
|
||||
void showWarn(WINPR_FORMAT_ARG const char* fmt, ...);
|
||||
void showWarn(const std::string& info);
|
||||
|
||||
WINPR_ATTR_FORMAT_ARG(2, 3)
|
||||
void showError(WINPR_FORMAT_ARG const char* fmt, ...);
|
||||
void showError(const std::string& error);
|
||||
|
||||
void show(SdlConnectionDialogWrapper::MsgType type, const std::string& msg);
|
||||
|
||||
void show(bool visible = true);
|
||||
|
||||
void handleShow();
|
||||
|
||||
private:
|
||||
class EventArg
|
||||
{
|
||||
public:
|
||||
explicit EventArg(bool visible);
|
||||
explicit EventArg(const std::string& title);
|
||||
EventArg(SdlConnectionDialogWrapper::MsgType type, const std::string& msg, bool visible);
|
||||
|
||||
[[nodiscard]] bool hasTitle() const;
|
||||
[[nodiscard]] const std::string& title() const;
|
||||
|
||||
[[nodiscard]] bool hasMessage() const;
|
||||
[[nodiscard]] const std::string& message() const;
|
||||
|
||||
[[nodiscard]] bool hasType() const;
|
||||
[[nodiscard]] SdlConnectionDialogWrapper::MsgType type() const;
|
||||
|
||||
[[nodiscard]] bool hasVisibility() const;
|
||||
[[nodiscard]] bool visible() const;
|
||||
|
||||
[[nodiscard]] std::string str() const;
|
||||
|
||||
private:
|
||||
std::string _title;
|
||||
std::string _message;
|
||||
SdlConnectionDialogWrapper::MsgType _type = MSG_NONE;
|
||||
bool _visible = false;
|
||||
uint32_t _mask = 0;
|
||||
};
|
||||
void push(EventArg&& arg);
|
||||
|
||||
mutable std::mutex _mux;
|
||||
std::unique_ptr<SDLConnectionDialog> _connection_dialog;
|
||||
std::queue<EventArg> _queue;
|
||||
wLog* _log = nullptr;
|
||||
};
|
||||
648
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_dialogs.cpp
vendored
Normal file
648
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_dialogs.cpp
vendored
Normal file
@@ -0,0 +1,648 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/utils/smartcardlogon.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "../sdl_context.hpp"
|
||||
#include "sdl_dialogs.hpp"
|
||||
#include "sdl_input_widget_pair.hpp"
|
||||
#include "sdl_input_widget_pair_list.hpp"
|
||||
#include "sdl_select.hpp"
|
||||
#include "sdl_select_list.hpp"
|
||||
#include "sdl_connection_dialog.hpp"
|
||||
|
||||
enum
|
||||
{
|
||||
SHOW_DIALOG_ACCEPT_REJECT = 1,
|
||||
SHOW_DIALOG_TIMED_ACCEPT = 2
|
||||
};
|
||||
|
||||
static const char* type_str_for_flags(UINT32 flags)
|
||||
{
|
||||
const char* type = "RDP-Server";
|
||||
|
||||
if (flags & VERIFY_CERT_FLAG_GATEWAY)
|
||||
type = "RDP-Gateway";
|
||||
|
||||
if (flags & VERIFY_CERT_FLAG_REDIRECT)
|
||||
type = "RDP-Redirect";
|
||||
return type;
|
||||
}
|
||||
|
||||
static BOOL sdl_wait_for_result(rdpContext* context, Uint32 type, SDL_Event* result)
|
||||
{
|
||||
const SDL_Event empty = {};
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(result);
|
||||
|
||||
while (!freerdp_shall_disconnect_context(context))
|
||||
{
|
||||
*result = empty;
|
||||
const int rc = SDL_PeepEvents(result, 1, SDL_GETEVENT, type, type);
|
||||
if (rc > 0)
|
||||
return TRUE;
|
||||
Sleep(1);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int sdl_show_dialog(rdpContext* context, const char* title, const char* message,
|
||||
Sint32 flags)
|
||||
{
|
||||
SDL_Event event = {};
|
||||
|
||||
if (!sdl_push_user_event(SDL_EVENT_USER_SHOW_DIALOG, title, message, flags))
|
||||
return 0;
|
||||
|
||||
if (!sdl_wait_for_result(context, SDL_EVENT_USER_SHOW_RESULT, &event))
|
||||
return 0;
|
||||
|
||||
return event.user.code;
|
||||
}
|
||||
|
||||
BOOL sdl_authenticate_ex(freerdp* instance, char** username, char** password, char** domain,
|
||||
rdp_auth_reason reason)
|
||||
{
|
||||
SDL_Event event = {};
|
||||
BOOL res = FALSE;
|
||||
|
||||
const char* target = freerdp_settings_get_server_name(instance->context->settings);
|
||||
switch (reason)
|
||||
{
|
||||
case AUTH_RDSTLS:
|
||||
case AUTH_NLA:
|
||||
break;
|
||||
|
||||
case AUTH_TLS:
|
||||
case AUTH_RDP:
|
||||
case AUTH_SMARTCARD_PIN: /* in this case password is pin code */
|
||||
if ((*username) && (*password))
|
||||
return TRUE;
|
||||
break;
|
||||
case GW_AUTH_HTTP:
|
||||
case GW_AUTH_RDG:
|
||||
case GW_AUTH_RPC:
|
||||
target =
|
||||
freerdp_settings_get_string(instance->context->settings, FreeRDP_GatewayHostname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
char* title = nullptr;
|
||||
size_t titlesize = 0;
|
||||
winpr_asprintf(&title, &titlesize, "Credentials required for %s", target);
|
||||
|
||||
CStringPtr guard(title, free);
|
||||
char* u = nullptr;
|
||||
char* d = nullptr;
|
||||
char* p = nullptr;
|
||||
|
||||
assert(username);
|
||||
assert(domain);
|
||||
assert(password);
|
||||
|
||||
u = *username;
|
||||
d = *domain;
|
||||
p = *password;
|
||||
|
||||
if (!sdl_push_user_event(SDL_EVENT_USER_AUTH_DIALOG, title, u, d, p, reason))
|
||||
return res;
|
||||
|
||||
if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_AUTH_RESULT, &event))
|
||||
return res;
|
||||
|
||||
auto arg = reinterpret_cast<SDL_UserAuthArg*>(event.padding);
|
||||
|
||||
res = arg->result > 0;
|
||||
|
||||
free(*username);
|
||||
free(*domain);
|
||||
free(*password);
|
||||
*username = arg->user;
|
||||
*domain = arg->domain;
|
||||
*password = arg->password;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL sdl_choose_smartcard(freerdp* instance, SmartcardCertInfo** cert_list, DWORD count,
|
||||
DWORD* choice, BOOL gateway)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(cert_list);
|
||||
WINPR_ASSERT(choice);
|
||||
|
||||
std::vector<std::string> strlist;
|
||||
std::vector<const char*> list;
|
||||
for (DWORD i = 0; i < count; i++)
|
||||
{
|
||||
const SmartcardCertInfo* cert = cert_list[i];
|
||||
char* reader = ConvertWCharToUtf8Alloc(cert->reader, nullptr);
|
||||
char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, nullptr);
|
||||
|
||||
char* msg = nullptr;
|
||||
size_t len = 0;
|
||||
|
||||
winpr_asprintf(&msg, &len,
|
||||
"%s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s",
|
||||
container_name, reader, cert->userHint, cert->domainHint, cert->subject,
|
||||
cert->issuer, cert->upn);
|
||||
|
||||
strlist.emplace_back(msg);
|
||||
free(msg);
|
||||
free(reader);
|
||||
free(container_name);
|
||||
|
||||
auto& m = strlist.back();
|
||||
list.push_back(m.c_str());
|
||||
}
|
||||
|
||||
SDL_Event event = {};
|
||||
const char* title = "Select a logon smartcard certificate";
|
||||
if (gateway)
|
||||
title = "Select a gateway logon smartcard certificate";
|
||||
if (!sdl_push_user_event(SDL_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
|
||||
return res;
|
||||
|
||||
if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event))
|
||||
return res;
|
||||
|
||||
res = (event.user.code >= 0);
|
||||
*choice = static_cast<DWORD>(event.user.code);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
SSIZE_T sdl_retry_dialog(freerdp* instance, const char* what, size_t current,
|
||||
[[maybe_unused]] void* userarg)
|
||||
{
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(instance->context);
|
||||
WINPR_ASSERT(what);
|
||||
|
||||
auto sdl = get_context(instance->context);
|
||||
auto settings = instance->context->settings;
|
||||
const BOOL enabled = freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled);
|
||||
const size_t delay = freerdp_settings_get_uint32(settings, FreeRDP_TcpConnectTimeout);
|
||||
|
||||
sdl->getDialog().setTitle("Retry connection to %s",
|
||||
freerdp_settings_get_server_name(instance->context->settings));
|
||||
|
||||
if ((strcmp(what, "arm-transport") != 0) && (strcmp(what, "connection") != 0))
|
||||
{
|
||||
sdl->getDialog().showError("Unknown module %s, aborting", what);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (current == 0)
|
||||
{
|
||||
if (strcmp(what, "arm-transport") == 0)
|
||||
sdl->getDialog().showWarn("[%s] Starting your VM. It may take up to 5 minutes", what);
|
||||
}
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
sdl->getDialog().showError(
|
||||
"Automatic reconnection disabled, terminating. Try to connect again later");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const size_t max = freerdp_settings_get_uint32(settings, FreeRDP_AutoReconnectMaxRetries);
|
||||
if (current >= max)
|
||||
{
|
||||
sdl->getDialog().showError(
|
||||
"[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
|
||||
"tech support for help if this keeps happening.",
|
||||
what);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdl->getDialog().showInfo("[%s] retry %" PRIuz "/%" PRIuz ", delaying %" PRIuz
|
||||
"ms before next attempt",
|
||||
what, current + 1, max, delay);
|
||||
return WINPR_ASSERTING_INT_CAST(ssize_t, delay);
|
||||
}
|
||||
|
||||
BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
|
||||
BOOL isDisplayMandatory, BOOL isConsentMandatory, size_t length,
|
||||
const WCHAR* wmessage)
|
||||
{
|
||||
if (!isDisplayMandatory)
|
||||
return TRUE;
|
||||
|
||||
char* title = nullptr;
|
||||
size_t len = 0;
|
||||
winpr_asprintf(&title, &len, "[gateway]");
|
||||
|
||||
Sint32 flags = 0;
|
||||
if (isConsentMandatory)
|
||||
flags = SHOW_DIALOG_ACCEPT_REJECT;
|
||||
else if (isDisplayMandatory)
|
||||
flags = SHOW_DIALOG_TIMED_ACCEPT;
|
||||
char* message = ConvertWCharNToUtf8Alloc(wmessage, length, nullptr);
|
||||
|
||||
const int rc = sdl_show_dialog(instance->context, title, message, flags);
|
||||
free(title);
|
||||
free(message);
|
||||
return rc > 0;
|
||||
}
|
||||
|
||||
int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
|
||||
{
|
||||
int rc = -1;
|
||||
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;
|
||||
|
||||
/* ignore LOGON_MSG_SESSION_CONTINUE message */
|
||||
if (type == LOGON_MSG_SESSION_CONTINUE)
|
||||
return 0;
|
||||
|
||||
char* title = nullptr;
|
||||
size_t tlen = 0;
|
||||
winpr_asprintf(&title, &tlen, "[%s] info",
|
||||
freerdp_settings_get_server_name(instance->context->settings));
|
||||
|
||||
char* message = nullptr;
|
||||
size_t mlen = 0;
|
||||
winpr_asprintf(&message, &mlen, "Logon Error Info %s [%s]", str_data, str_type);
|
||||
|
||||
rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
|
||||
free(title);
|
||||
free(message);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static DWORD sdl_show_ceritifcate_dialog(rdpContext* context, const char* title,
|
||||
const char* message)
|
||||
{
|
||||
if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
|
||||
return 0;
|
||||
|
||||
SDL_Event event = {};
|
||||
if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
|
||||
return 0;
|
||||
return static_cast<DWORD>(event.user.code);
|
||||
}
|
||||
|
||||
static char* sdl_pem_cert(const char* pem)
|
||||
{
|
||||
rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
|
||||
char* fp = freerdp_certificate_get_fingerprint(cert);
|
||||
char* start = freerdp_certificate_get_validity(cert, TRUE);
|
||||
char* end = freerdp_certificate_get_validity(cert, FALSE);
|
||||
freerdp_certificate_free(cert);
|
||||
|
||||
char* str = nullptr;
|
||||
size_t slen = 0;
|
||||
winpr_asprintf(&str, &slen,
|
||||
"Valid from: %s\n"
|
||||
"Valid to: %s\n"
|
||||
"Thumbprint: %s\n",
|
||||
start, end, fp);
|
||||
free(fp);
|
||||
free(start);
|
||||
free(end);
|
||||
return str;
|
||||
}
|
||||
|
||||
DWORD sdl_verify_changed_certificate_ex(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)
|
||||
{
|
||||
const char* type = type_str_for_flags(flags);
|
||||
|
||||
WINPR_ASSERT(instance);
|
||||
WINPR_ASSERT(instance->context);
|
||||
WINPR_ASSERT(instance->context->settings);
|
||||
|
||||
/* Newer versions of FreeRDP allow exposing the whole PEM by setting
|
||||
* FreeRDP_CertificateCallbackPreferPEM to TRUE
|
||||
*/
|
||||
char* new_fp_str = nullptr;
|
||||
size_t len = 0;
|
||||
if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
|
||||
new_fp_str = sdl_pem_cert(new_fingerprint);
|
||||
else
|
||||
winpr_asprintf(&new_fp_str, &len, "Thumbprint: %s\n", new_fingerprint);
|
||||
|
||||
/* Newer versions of FreeRDP allow exposing the whole PEM by setting
|
||||
* FreeRDP_CertificateCallbackPreferPEM to TRUE
|
||||
*/
|
||||
char* old_fp_str = nullptr;
|
||||
size_t olen = 0;
|
||||
if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
|
||||
old_fp_str = sdl_pem_cert(old_fingerprint);
|
||||
else
|
||||
winpr_asprintf(&old_fp_str, &olen, "Thumbprint: %s\n", old_fingerprint);
|
||||
|
||||
const char* collission_str = "";
|
||||
if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
|
||||
{
|
||||
collission_str =
|
||||
"A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
|
||||
"If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
|
||||
"The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
|
||||
"All manually accepted certificates must be reconfirmed!\n"
|
||||
"\n";
|
||||
}
|
||||
|
||||
char* title = nullptr;
|
||||
size_t tlen = 0;
|
||||
winpr_asprintf(&title, &tlen, "Certificate for %s:%" PRIu16 " (%s) has changed", host, port,
|
||||
type);
|
||||
|
||||
char* message = nullptr;
|
||||
size_t mlen = 0;
|
||||
winpr_asprintf(&message, &mlen,
|
||||
"New Certificate details:\n"
|
||||
"Common Name: %s\n"
|
||||
"Subject: %s\n"
|
||||
"Issuer: %s\n"
|
||||
"%s\n"
|
||||
"Old Certificate details:\n"
|
||||
"Subject: %s\n"
|
||||
"Issuer: %s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"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",
|
||||
common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
|
||||
collission_str);
|
||||
|
||||
const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
|
||||
free(title);
|
||||
free(message);
|
||||
free(new_fp_str);
|
||||
free(old_fp_str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
DWORD sdl_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 = type_str_for_flags(flags);
|
||||
|
||||
/* Newer versions of FreeRDP allow exposing the whole PEM by setting
|
||||
* FreeRDP_CertificateCallbackPreferPEM to TRUE
|
||||
*/
|
||||
char* fp_str = nullptr;
|
||||
size_t len = 0;
|
||||
if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
|
||||
fp_str = sdl_pem_cert(fingerprint);
|
||||
else
|
||||
winpr_asprintf(&fp_str, &len, "Thumbprint: %s\n", fingerprint);
|
||||
|
||||
char* title = nullptr;
|
||||
size_t tlen = 0;
|
||||
winpr_asprintf(&title, &tlen, "New certificate for %s:%" PRIu16 " (%s)", host, port, type);
|
||||
|
||||
char* message = nullptr;
|
||||
size_t mlen = 0;
|
||||
winpr_asprintf(
|
||||
&message, &mlen,
|
||||
"Common Name: %s\n"
|
||||
"Subject: %s\n"
|
||||
"Issuer: %s\n"
|
||||
"%s\n"
|
||||
"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",
|
||||
common_name, subject, issuer, fp_str);
|
||||
|
||||
const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
|
||||
free(fp_str);
|
||||
free(title);
|
||||
free(message);
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL sdl_cert_dialog_show(const char* title, const char* message)
|
||||
{
|
||||
int buttonid = -1;
|
||||
enum
|
||||
{
|
||||
BUTTONID_CERT_ACCEPT_PERMANENT = 23,
|
||||
BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
|
||||
BUTTONID_CERT_DENY = 25
|
||||
};
|
||||
const SDL_MessageBoxButtonData buttons[] = {
|
||||
{ 0, BUTTONID_CERT_ACCEPT_PERMANENT, "permanent" },
|
||||
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY, "temporary" },
|
||||
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY, "cancel" }
|
||||
};
|
||||
|
||||
const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING, nullptr, title, message,
|
||||
ARRAYSIZE(buttons), buttons, nullptr };
|
||||
const int rc = SDL_ShowMessageBox(&data, &buttonid);
|
||||
|
||||
Sint32 value = -1;
|
||||
if (rc < 0)
|
||||
value = 0;
|
||||
else
|
||||
{
|
||||
switch (buttonid)
|
||||
{
|
||||
case BUTTONID_CERT_ACCEPT_PERMANENT:
|
||||
value = 1;
|
||||
break;
|
||||
case BUTTONID_CERT_ACCEPT_TEMPORARY:
|
||||
value = 2;
|
||||
break;
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
|
||||
}
|
||||
|
||||
BOOL sdl_message_dialog_show(const char* title, const char* message, Sint32 flags)
|
||||
{
|
||||
int buttonid = -1;
|
||||
enum
|
||||
{
|
||||
BUTTONID_SHOW_ACCEPT = 24,
|
||||
BUTTONID_SHOW_DENY = 25
|
||||
};
|
||||
const SDL_MessageBoxButtonData buttons[] = {
|
||||
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT, "accept" },
|
||||
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY, "cancel" }
|
||||
};
|
||||
|
||||
const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
|
||||
const SDL_MessageBoxData data = {
|
||||
SDL_MESSAGEBOX_WARNING, nullptr, title, message, button_cnt, buttons, nullptr
|
||||
};
|
||||
const int rc = SDL_ShowMessageBox(&data, &buttonid);
|
||||
|
||||
Sint32 value = -1;
|
||||
if (rc < 0)
|
||||
value = 0;
|
||||
else
|
||||
{
|
||||
switch (buttonid)
|
||||
{
|
||||
case BUTTONID_SHOW_ACCEPT:
|
||||
value = 1;
|
||||
break;
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
|
||||
}
|
||||
|
||||
BOOL sdl_auth_dialog_show(const SDL_UserAuthArg* args)
|
||||
{
|
||||
const std::vector<std::string> auth = { "Username: ", "Domain: ",
|
||||
"Password: " };
|
||||
const std::vector<std::string> authPin = { "Device: ", "PIN: " };
|
||||
const std::vector<std::string> gw = { "GatewayUsername: ", "GatewayDomain: ",
|
||||
"GatewayPassword: " };
|
||||
std::vector<std::string> prompt;
|
||||
Sint32 rc = -1;
|
||||
|
||||
switch (args->result)
|
||||
{
|
||||
case AUTH_SMARTCARD_PIN:
|
||||
prompt = authPin;
|
||||
break;
|
||||
case AUTH_RDSTLS:
|
||||
case AUTH_TLS:
|
||||
case AUTH_RDP:
|
||||
case AUTH_NLA:
|
||||
prompt = auth;
|
||||
break;
|
||||
case GW_AUTH_HTTP:
|
||||
case GW_AUTH_RDG:
|
||||
case GW_AUTH_RPC:
|
||||
prompt = gw;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
|
||||
if (!prompt.empty())
|
||||
{
|
||||
std::vector<std::string> initial{ args->user ? args->user : "Smartcard", "" };
|
||||
std::vector<Uint32> flags = { SdlInputWidgetPair::SDL_INPUT_READONLY,
|
||||
SdlInputWidgetPair::SDL_INPUT_MASK };
|
||||
if (args->result != AUTH_SMARTCARD_PIN)
|
||||
{
|
||||
if (args->result == AUTH_RDSTLS)
|
||||
{
|
||||
initial = { args->user ? args->user : "", args->password ? args->password : "" };
|
||||
flags = { 0, SdlInputWidgetPair::SDL_INPUT_MASK };
|
||||
}
|
||||
else
|
||||
{
|
||||
initial = { args->user ? args->user : "", args->domain ? args->domain : "",
|
||||
args->password ? args->password : "" };
|
||||
flags = { 0, 0, SdlInputWidgetPair::SDL_INPUT_MASK };
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t selected = -1;
|
||||
switch (args->result)
|
||||
{
|
||||
case AUTH_SMARTCARD_PIN:
|
||||
case AUTH_RDSTLS:
|
||||
break;
|
||||
default:
|
||||
if (args->user)
|
||||
{
|
||||
selected++;
|
||||
if (args->domain)
|
||||
selected++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
SdlInputWidgetPairList ilist(args->title, prompt, initial, flags, selected);
|
||||
rc = ilist.run(result);
|
||||
}
|
||||
|
||||
if ((result.size() < prompt.size()))
|
||||
rc = -1;
|
||||
|
||||
char* user = nullptr;
|
||||
char* domain = nullptr;
|
||||
char* pwd = nullptr;
|
||||
if (rc > 0)
|
||||
{
|
||||
user = _strdup(result.at(0).c_str());
|
||||
if (args->result == AUTH_SMARTCARD_PIN)
|
||||
pwd = _strdup(result.at(1).c_str());
|
||||
else
|
||||
{
|
||||
domain = _strdup(result.at(1).c_str());
|
||||
pwd = _strdup(result.at(2).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return sdl_push_user_event(SDL_EVENT_USER_AUTH_RESULT, user, domain, pwd, rc);
|
||||
}
|
||||
|
||||
BOOL sdl_scard_dialog_show(const char* title, Sint32 count, const char** list)
|
||||
{
|
||||
std::vector<std::string> vlist;
|
||||
vlist.reserve(WINPR_ASSERTING_INT_CAST(size_t, count));
|
||||
for (Sint32 x = 0; x < count; x++)
|
||||
vlist.emplace_back(list[x]);
|
||||
SdlSelectList slist(title, vlist);
|
||||
Sint32 value = slist.run();
|
||||
return sdl_push_user_event(SDL_EVENT_USER_SCARD_RESULT, value);
|
||||
}
|
||||
|
||||
void sdl_dialogs_uninit()
|
||||
{
|
||||
TTF_Quit();
|
||||
}
|
||||
|
||||
void sdl_dialogs_init()
|
||||
{
|
||||
TTF_Init();
|
||||
}
|
||||
59
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_dialogs.hpp
vendored
Normal file
59
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_dialogs.hpp
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#include "../sdl_types.hpp"
|
||||
#include "../sdl_utils.hpp"
|
||||
|
||||
[[nodiscard]] BOOL sdl_authenticate_ex(freerdp* instance, char** username, char** password,
|
||||
char** domain, rdp_auth_reason reason);
|
||||
[[nodiscard]] BOOL sdl_choose_smartcard(freerdp* instance, SmartcardCertInfo** cert_list,
|
||||
DWORD count, DWORD* choice, BOOL gateway);
|
||||
|
||||
[[nodiscard]] SSIZE_T sdl_retry_dialog(freerdp* instance, const char* what, size_t current,
|
||||
void* userarg);
|
||||
|
||||
[[nodiscard]] DWORD sdl_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);
|
||||
|
||||
[[nodiscard]] DWORD
|
||||
sdl_verify_changed_certificate_ex(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);
|
||||
|
||||
[[nodiscard]] int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type);
|
||||
|
||||
[[nodiscard]] BOOL sdl_present_gateway_message(freerdp* instance, UINT32 type,
|
||||
BOOL isDisplayMandatory, BOOL isConsentMandatory,
|
||||
size_t length, const WCHAR* message);
|
||||
|
||||
[[nodiscard]] BOOL sdl_message_dialog_show(const char* title, const char* message, Sint32 flags);
|
||||
[[nodiscard]] BOOL sdl_cert_dialog_show(const char* title, const char* message);
|
||||
[[nodiscard]] BOOL sdl_scard_dialog_show(const char* title, Sint32 count, const char** list);
|
||||
[[nodiscard]] BOOL sdl_auth_dialog_show(const SDL_UserAuthArg* args);
|
||||
|
||||
void sdl_dialogs_init();
|
||||
void sdl_dialogs_uninit();
|
||||
52
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget.cpp
vendored
Normal file
52
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget.cpp
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "sdl_input_widget.hpp"
|
||||
|
||||
SdlInputWidget::SdlInputWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect)
|
||||
: SdlSelectableWidget(renderer, rect)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
SdlInputWidget::~SdlInputWidget() = default;
|
||||
|
||||
std::string SdlInputWidget::text() const
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
|
||||
void SdlInputWidget::init()
|
||||
{
|
||||
_backgroundcolor = { 0x56, 0x56, 0x56, 0xff };
|
||||
_fontcolor = { 0xd1, 0xcf, 0xcd, 0xff };
|
||||
_highlightcolor = { 0x80, 0, 0, 0x60 };
|
||||
_mouseovercolor = { 0, 0x80, 0, 0x60 };
|
||||
}
|
||||
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
SdlInputWidget::SdlInputWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect,
|
||||
SDL_IOStream* ops)
|
||||
: SdlSelectableWidget(renderer, rect, ops)
|
||||
{
|
||||
init();
|
||||
}
|
||||
#endif
|
||||
|
||||
SdlInputWidget::SdlInputWidget(SdlInputWidget&& other) noexcept = default;
|
||||
43
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget.hpp
vendored
Normal file
43
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget.hpp
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdl_selectable_widget.hpp"
|
||||
|
||||
class SdlInputWidget : public SdlSelectableWidget
|
||||
{
|
||||
public:
|
||||
SdlInputWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect);
|
||||
SdlInputWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect,
|
||||
SDL_IOStream* ops);
|
||||
|
||||
SdlInputWidget(SdlInputWidget&& other) noexcept;
|
||||
SdlInputWidget(const SdlInputWidget& other) = delete;
|
||||
|
||||
SdlInputWidget& operator=(const SdlInputWidget& other) = delete;
|
||||
SdlInputWidget& operator=(SdlInputWidget&& other) noexcept = delete;
|
||||
|
||||
~SdlInputWidget() override;
|
||||
|
||||
[[nodiscard]] std::string text() const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
};
|
||||
129
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair.cpp
vendored
Normal file
129
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair.cpp
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "sdl_input_widget_pair.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
|
||||
#include "sdl_widget.hpp"
|
||||
#include "sdl_button.hpp"
|
||||
#include "sdl_buttons.hpp"
|
||||
|
||||
SdlInputWidgetPair::SdlInputWidgetPair(std::shared_ptr<SDL_Renderer>& renderer,
|
||||
const std::string& label, const std::string& initial,
|
||||
Uint32 flags, size_t offset, size_t width, size_t height)
|
||||
: _flags(flags), _label(renderer, { 0, static_cast<float>(offset * (height + _vpadding)),
|
||||
static_cast<float>(width), static_cast<float>(height) }),
|
||||
_input(renderer, { static_cast<float>(width + _hpadding),
|
||||
static_cast<float>(offset * (height + _vpadding)),
|
||||
static_cast<float>(width), static_cast<float>(height) })
|
||||
{
|
||||
std::ignore = _label.update_text(label);
|
||||
std::ignore = update_input_text(initial);
|
||||
}
|
||||
|
||||
SdlInputWidgetPair::SdlInputWidgetPair(SdlInputWidgetPair&& other) noexcept = default;
|
||||
|
||||
bool SdlInputWidgetPair::set_mouseover(bool mouseOver)
|
||||
{
|
||||
if (readonly())
|
||||
return true;
|
||||
return _input.mouseover(mouseOver);
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::set_highlight(bool highlight)
|
||||
{
|
||||
if (readonly())
|
||||
return true;
|
||||
return _input.highlight(highlight);
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::set_str(const std::string& text)
|
||||
{
|
||||
if (readonly())
|
||||
return true;
|
||||
return update_input_text(text);
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::remove_str(size_t count)
|
||||
{
|
||||
if (readonly())
|
||||
return true;
|
||||
|
||||
auto text = _text;
|
||||
if (text.empty())
|
||||
return true;
|
||||
|
||||
auto newsize = text.size() - std::min<size_t>(text.size(), count);
|
||||
return update_input_text(text.substr(0, newsize));
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::append_str(const std::string& text)
|
||||
{
|
||||
if (readonly())
|
||||
return true;
|
||||
|
||||
auto itext = _text;
|
||||
itext.append(text);
|
||||
return update_input_text(itext);
|
||||
}
|
||||
|
||||
const SDL_FRect& SdlInputWidgetPair::input_rect() const
|
||||
{
|
||||
return _input.rect();
|
||||
}
|
||||
|
||||
std::string SdlInputWidgetPair::value() const
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::readonly() const
|
||||
{
|
||||
return (_flags & SDL_INPUT_READONLY) != 0;
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::update()
|
||||
{
|
||||
// TODO: Draw the pair area
|
||||
if (!_label.update())
|
||||
return false;
|
||||
if (!_input.update())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPair::update_input_text(const std::string& txt)
|
||||
{
|
||||
_text = txt;
|
||||
auto text = txt;
|
||||
|
||||
if (_flags & SDL_INPUT_MASK)
|
||||
{
|
||||
std::fill(text.begin(), text.end(), '*');
|
||||
}
|
||||
|
||||
return _input.update_text(text);
|
||||
}
|
||||
73
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair.hpp
vendored
Normal file
73
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair.hpp
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include "sdl_widget.hpp"
|
||||
#include "sdl_input_widget.hpp"
|
||||
|
||||
class SdlInputWidgetPair
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
SDL_INPUT_MASK = 1,
|
||||
SDL_INPUT_READONLY = 2
|
||||
};
|
||||
|
||||
SdlInputWidgetPair(std::shared_ptr<SDL_Renderer>& renderer, const std::string& label,
|
||||
const std::string& initial, Uint32 flags, size_t offset, size_t width,
|
||||
size_t height);
|
||||
SdlInputWidgetPair(SdlInputWidgetPair&& other) noexcept;
|
||||
SdlInputWidgetPair(const SdlInputWidgetPair& other) = delete;
|
||||
~SdlInputWidgetPair() = default;
|
||||
|
||||
SdlInputWidgetPair& operator=(const SdlInputWidgetPair& other) = delete;
|
||||
SdlInputWidgetPair& operator=(SdlInputWidgetPair&& other) = delete;
|
||||
|
||||
bool set_mouseover(bool mouseOver);
|
||||
bool set_highlight(bool highlight);
|
||||
|
||||
[[nodiscard]] bool set_str(const std::string& text);
|
||||
[[nodiscard]] bool remove_str(size_t count);
|
||||
[[nodiscard]] bool append_str(const std::string& text);
|
||||
|
||||
[[nodiscard]] const SDL_FRect& input_rect() const;
|
||||
[[nodiscard]] std::string value() const;
|
||||
|
||||
[[nodiscard]] bool readonly() const;
|
||||
|
||||
[[nodiscard]] bool update();
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool update_input_text(const std::string& txt);
|
||||
|
||||
Uint32 _vpadding = 5;
|
||||
Uint32 _hpadding = 10;
|
||||
|
||||
private:
|
||||
Uint32 _flags{};
|
||||
SdlWidget _label;
|
||||
SdlInputWidget _input;
|
||||
std::string _text;
|
||||
};
|
||||
313
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair_list.cpp
vendored
Normal file
313
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair_list.cpp
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include "sdl_widget_list.hpp"
|
||||
#include "sdl_input_widget_pair_list.hpp"
|
||||
|
||||
static const Uint32 vpadding = 5;
|
||||
|
||||
SdlInputWidgetPairList::SdlInputWidgetPairList(const std::string& title,
|
||||
const std::vector<std::string>& labels,
|
||||
const std::vector<std::string>& initial,
|
||||
const std::vector<Uint32>& flags, ssize_t selected)
|
||||
{
|
||||
assert(labels.size() == initial.size());
|
||||
assert(labels.size() == flags.size());
|
||||
const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
|
||||
const std::vector<std::string> buttonlabels = { "accept", "cancel" };
|
||||
|
||||
const size_t widget_width = 300;
|
||||
const size_t widget_heigth = 50;
|
||||
|
||||
const size_t total_width = widget_width + widget_width;
|
||||
const size_t input_height = labels.size() * (widget_heigth + vpadding) + vpadding;
|
||||
const size_t total_height = input_height + widget_heigth;
|
||||
assert(total_width <= INT32_MAX);
|
||||
assert(total_height <= INT32_MAX);
|
||||
|
||||
if (reset(title, total_width, total_height))
|
||||
{
|
||||
for (size_t x = 0; x < labels.size(); x++)
|
||||
{
|
||||
auto widget =
|
||||
std::make_shared<SdlInputWidgetPair>(_renderer, labels.at(x), initial.at(x),
|
||||
flags.at(x), x, widget_width, widget_heigth);
|
||||
m_list.emplace_back(widget);
|
||||
}
|
||||
|
||||
std::ignore = _buttons.populate(
|
||||
_renderer, buttonlabels, buttonids, total_width, static_cast<Sint32>(input_height),
|
||||
static_cast<Sint32>(widget_width), static_cast<Sint32>(widget_heigth));
|
||||
_buttons.set_highlight(0);
|
||||
m_currentActiveTextInput = selected;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t SdlInputWidgetPairList::next(ssize_t current)
|
||||
{
|
||||
size_t iteration = 0;
|
||||
auto val = static_cast<size_t>(current);
|
||||
|
||||
do
|
||||
{
|
||||
if (iteration >= m_list.size())
|
||||
return -1;
|
||||
|
||||
if (iteration == 0)
|
||||
{
|
||||
if (current < 0)
|
||||
val = 0;
|
||||
else
|
||||
val++;
|
||||
}
|
||||
else
|
||||
val++;
|
||||
iteration++;
|
||||
val %= m_list.size();
|
||||
} while (!valid(static_cast<ssize_t>(val)));
|
||||
return static_cast<ssize_t>(val);
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPairList::valid(ssize_t current) const
|
||||
{
|
||||
if (current < 0)
|
||||
return false;
|
||||
auto s = static_cast<size_t>(current);
|
||||
if (s >= m_list.size())
|
||||
return false;
|
||||
return !m_list.at(s)->readonly();
|
||||
}
|
||||
|
||||
std::shared_ptr<SdlInputWidgetPair> SdlInputWidgetPairList::get(ssize_t index)
|
||||
{
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
auto s = static_cast<size_t>(index);
|
||||
if (s >= m_list.size())
|
||||
return nullptr;
|
||||
return m_list.at(s);
|
||||
}
|
||||
|
||||
SdlInputWidgetPairList::~SdlInputWidgetPairList()
|
||||
{
|
||||
m_list.clear();
|
||||
_buttons.clear();
|
||||
}
|
||||
|
||||
bool SdlInputWidgetPairList::updateInternal()
|
||||
{
|
||||
for (auto& btn : m_list)
|
||||
{
|
||||
if (!btn->update())
|
||||
return false;
|
||||
if (!btn->update())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t SdlInputWidgetPairList::get_index(const SDL_MouseButtonEvent& button)
|
||||
{
|
||||
const auto x = button.x;
|
||||
const auto y = button.y;
|
||||
for (size_t i = 0; i < m_list.size(); i++)
|
||||
{
|
||||
auto& cur = m_list.at(i);
|
||||
auto r = cur->input_rect();
|
||||
|
||||
if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
|
||||
return WINPR_ASSERTING_INT_CAST(ssize_t, i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SdlInputWidgetPairList::run(std::vector<std::string>& result)
|
||||
{
|
||||
int res = -1;
|
||||
ssize_t LastActiveTextInput = -1;
|
||||
m_currentActiveTextInput = next(m_currentActiveTextInput);
|
||||
|
||||
if (!_window || !_renderer)
|
||||
return -2;
|
||||
|
||||
if (!SDL_StartTextInput(_window.get()))
|
||||
return -3;
|
||||
|
||||
try
|
||||
{
|
||||
bool running = true;
|
||||
while (running)
|
||||
{
|
||||
if (!update())
|
||||
throw;
|
||||
|
||||
SDL_Event event = {};
|
||||
if (!SDL_WaitEvent(&event))
|
||||
throw;
|
||||
do
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_KEY_UP:
|
||||
{
|
||||
switch (event.key.key)
|
||||
{
|
||||
case SDLK_BACKSPACE:
|
||||
{
|
||||
auto cur = get(m_currentActiveTextInput);
|
||||
if (cur)
|
||||
{
|
||||
if ((event.key.mod & SDL_KMOD_CTRL) != 0)
|
||||
{
|
||||
if (!cur->set_str(""))
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cur->remove_str(1))
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_TAB:
|
||||
m_currentActiveTextInput = next(m_currentActiveTextInput);
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_RETURN2:
|
||||
case SDLK_KP_ENTER:
|
||||
running = false;
|
||||
res = INPUT_BUTTON_ACCEPT;
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
running = false;
|
||||
res = INPUT_BUTTON_CANCEL;
|
||||
break;
|
||||
case SDLK_V:
|
||||
if ((event.key.mod & SDL_KMOD_CTRL) != 0)
|
||||
{
|
||||
auto cur = get(m_currentActiveTextInput);
|
||||
if (cur)
|
||||
{
|
||||
auto text = SDL_GetClipboardText();
|
||||
if (!cur->set_str(text))
|
||||
throw;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_TEXT_INPUT:
|
||||
{
|
||||
auto cur = get(m_currentActiveTextInput);
|
||||
if (cur)
|
||||
{
|
||||
if (!cur->append_str(event.text.text))
|
||||
throw;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
{
|
||||
auto TextInputIndex = get_index(event.button);
|
||||
for (auto& cur : m_list)
|
||||
{
|
||||
cur->set_mouseover(false);
|
||||
}
|
||||
if (TextInputIndex >= 0)
|
||||
{
|
||||
auto& cur = m_list.at(static_cast<size_t>(TextInputIndex));
|
||||
cur->set_mouseover(true);
|
||||
}
|
||||
|
||||
_buttons.set_mouseover(event.button.x, event.button.y);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
{
|
||||
auto val = get_index(event.button);
|
||||
if (valid(val))
|
||||
m_currentActiveTextInput = val;
|
||||
|
||||
auto button = _buttons.get_selected(event.button);
|
||||
if (button)
|
||||
{
|
||||
running = false;
|
||||
if (button->id() == INPUT_BUTTON_CANCEL)
|
||||
res = INPUT_BUTTON_CANCEL;
|
||||
else
|
||||
res = INPUT_BUTTON_ACCEPT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_QUIT:
|
||||
res = INPUT_BUTTON_CANCEL;
|
||||
running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (SDL_PollEvent(&event));
|
||||
|
||||
if (LastActiveTextInput != m_currentActiveTextInput)
|
||||
{
|
||||
LastActiveTextInput = m_currentActiveTextInput;
|
||||
}
|
||||
|
||||
for (auto& cur : m_list)
|
||||
{
|
||||
if (!cur->set_highlight(false))
|
||||
throw;
|
||||
}
|
||||
auto cur = get(m_currentActiveTextInput);
|
||||
if (cur)
|
||||
{
|
||||
if (!cur->set_highlight(true))
|
||||
throw;
|
||||
}
|
||||
|
||||
auto rc = SDL_RenderPresent(_renderer.get());
|
||||
if (!rc)
|
||||
{
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] SDL_RenderPresent failed with %s",
|
||||
__func__, SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& cur : m_list)
|
||||
result.push_back(cur->value());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
res = -2;
|
||||
}
|
||||
if (!SDL_StopTextInput(_window.get()))
|
||||
return -4;
|
||||
|
||||
return res;
|
||||
}
|
||||
63
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair_list.hpp
vendored
Normal file
63
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_input_widget_pair_list.hpp
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_widget_list.hpp"
|
||||
#include "sdl_input_widget_pair.hpp"
|
||||
#include "sdl_buttons.hpp"
|
||||
|
||||
class SdlInputWidgetPairList : public SdlWidgetList
|
||||
{
|
||||
public:
|
||||
SdlInputWidgetPairList(const std::string& title, const std::vector<std::string>& labels,
|
||||
const std::vector<std::string>& initial,
|
||||
const std::vector<Uint32>& flags, ssize_t selected = -1);
|
||||
SdlInputWidgetPairList(const SdlInputWidgetPairList& other) = delete;
|
||||
SdlInputWidgetPairList(SdlInputWidgetPairList&& other) = delete;
|
||||
|
||||
~SdlInputWidgetPairList() override;
|
||||
|
||||
SdlInputWidgetPairList& operator=(const SdlInputWidgetPairList& other) = delete;
|
||||
SdlInputWidgetPairList& operator=(SdlInputWidgetPairList&& other) = delete;
|
||||
|
||||
[[nodiscard]] int run(std::vector<std::string>& result);
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool updateInternal() override;
|
||||
[[nodiscard]] ssize_t get_index(const SDL_MouseButtonEvent& button);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
INPUT_BUTTON_ACCEPT = 1,
|
||||
INPUT_BUTTON_CANCEL = -2
|
||||
};
|
||||
|
||||
[[nodiscard]] ssize_t next(ssize_t current);
|
||||
[[nodiscard]] bool valid(ssize_t current) const;
|
||||
[[nodiscard]] std::shared_ptr<SdlInputWidgetPair> get(ssize_t index);
|
||||
|
||||
std::vector<std::shared_ptr<SdlInputWidgetPair>> m_list;
|
||||
ssize_t m_currentActiveTextInput = -1;
|
||||
};
|
||||
45
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select.cpp
vendored
Normal file
45
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select.cpp
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
|
||||
#include "sdl_select.hpp"
|
||||
#include "sdl_widget.hpp"
|
||||
#include "sdl_button.hpp"
|
||||
#include "sdl_buttons.hpp"
|
||||
#include "sdl_input_widget_pair_list.hpp"
|
||||
|
||||
SdlSelectWidget::SdlSelectWidget(std::shared_ptr<SDL_Renderer>& renderer, const std::string& label,
|
||||
const SDL_FRect& rect)
|
||||
: SdlSelectableWidget(renderer, rect)
|
||||
{
|
||||
_backgroundcolor = { 0x69, 0x66, 0x63, 0xff };
|
||||
_fontcolor = { 0xd1, 0xcf, 0xcd, 0xff };
|
||||
std::ignore = update_text(label);
|
||||
}
|
||||
|
||||
SdlSelectWidget::~SdlSelectWidget() = default;
|
||||
|
||||
SdlSelectWidget::SdlSelectWidget(SdlSelectWidget&& other) noexcept = default;
|
||||
39
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select.hpp
vendored
Normal file
39
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select.hpp
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include "sdl_selectable_widget.hpp"
|
||||
|
||||
class SdlSelectWidget : public SdlSelectableWidget
|
||||
{
|
||||
public:
|
||||
SdlSelectWidget(std::shared_ptr<SDL_Renderer>& renderer, const std::string& label,
|
||||
const SDL_FRect& rect);
|
||||
SdlSelectWidget(SdlSelectWidget&& other) noexcept;
|
||||
SdlSelectWidget(const SdlSelectWidget& other) = delete;
|
||||
~SdlSelectWidget() override;
|
||||
|
||||
SdlSelectWidget& operator=(const SdlSelectWidget& other) = delete;
|
||||
SdlSelectWidget& operator=(SdlSelectWidget&& other) = delete;
|
||||
};
|
||||
200
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select_list.cpp
vendored
Normal file
200
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select_list.cpp
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
#include <cassert>
|
||||
#include <winpr/cast.h>
|
||||
#include "sdl_select_list.hpp"
|
||||
#include "../sdl_utils.hpp"
|
||||
|
||||
static const Uint32 vpadding = 5;
|
||||
|
||||
SdlSelectList::SdlSelectList(const std::string& title, const std::vector<std::string>& labels)
|
||||
{
|
||||
const size_t widget_height = 50;
|
||||
const size_t widget_width = 600;
|
||||
|
||||
const size_t total_height = labels.size() * (widget_height + vpadding) + vpadding;
|
||||
const size_t height = total_height + widget_height;
|
||||
if (reset(title, widget_width, height))
|
||||
{
|
||||
SDL_FRect rect = { 0, 0, widget_width, widget_height };
|
||||
for (auto& label : labels)
|
||||
{
|
||||
_list.emplace_back(_renderer, label, rect);
|
||||
rect.y += widget_height + vpadding;
|
||||
}
|
||||
|
||||
const std::vector<int> buttonids = { INPUT_BUTTON_ACCEPT, INPUT_BUTTON_CANCEL };
|
||||
const std::vector<std::string> buttonlabels = { "accept", "cancel" };
|
||||
std::ignore = _buttons.populate(
|
||||
_renderer, buttonlabels, buttonids, widget_width, static_cast<Sint32>(total_height),
|
||||
static_cast<Sint32>(widget_width / 2), static_cast<Sint32>(widget_height));
|
||||
_buttons.set_highlight(0);
|
||||
}
|
||||
}
|
||||
|
||||
SdlSelectList::~SdlSelectList() = default;
|
||||
|
||||
int SdlSelectList::run()
|
||||
{
|
||||
int res = -2;
|
||||
ssize_t CurrentActiveTextInput = 0;
|
||||
bool running = true;
|
||||
|
||||
if (!_window || !_renderer)
|
||||
return -2;
|
||||
try
|
||||
{
|
||||
while (running)
|
||||
{
|
||||
if (!update())
|
||||
throw;
|
||||
|
||||
SDL_Event event = {};
|
||||
if (!SDL_WaitEvent(&event))
|
||||
throw;
|
||||
do
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
switch (event.key.key)
|
||||
{
|
||||
case SDLK_UP:
|
||||
case SDLK_BACKSPACE:
|
||||
if (CurrentActiveTextInput > 0)
|
||||
CurrentActiveTextInput--;
|
||||
else if (_list.empty())
|
||||
CurrentActiveTextInput = 0;
|
||||
else
|
||||
{
|
||||
auto s = _list.size();
|
||||
CurrentActiveTextInput =
|
||||
WINPR_ASSERTING_INT_CAST(ssize_t, s) - 1;
|
||||
}
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
case SDLK_TAB:
|
||||
if ((CurrentActiveTextInput < 0) || _list.empty())
|
||||
CurrentActiveTextInput = 0;
|
||||
else
|
||||
{
|
||||
auto s = _list.size();
|
||||
CurrentActiveTextInput++;
|
||||
if (s > 0)
|
||||
{
|
||||
CurrentActiveTextInput =
|
||||
CurrentActiveTextInput %
|
||||
WINPR_ASSERTING_INT_CAST(ssize_t, s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
case SDLK_RETURN2:
|
||||
case SDLK_KP_ENTER:
|
||||
running = false;
|
||||
res = static_cast<int>(CurrentActiveTextInput);
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
running = false;
|
||||
res = INPUT_BUTTON_CANCEL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
{
|
||||
auto TextInputIndex = get_index(event.button);
|
||||
reset_mouseover();
|
||||
if (TextInputIndex >= 0)
|
||||
{
|
||||
auto& cur = _list.at(WINPR_ASSERTING_INT_CAST(size_t, TextInputIndex));
|
||||
if (!cur.mouseover(true))
|
||||
throw;
|
||||
}
|
||||
|
||||
_buttons.set_mouseover(event.button.x, event.button.y);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
{
|
||||
auto button = _buttons.get_selected(event.button);
|
||||
if (button)
|
||||
{
|
||||
running = false;
|
||||
if (button->id() == INPUT_BUTTON_CANCEL)
|
||||
res = INPUT_BUTTON_CANCEL;
|
||||
else
|
||||
res = static_cast<int>(CurrentActiveTextInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentActiveTextInput = get_index(event.button);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_QUIT:
|
||||
res = INPUT_BUTTON_CANCEL;
|
||||
running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (SDL_PollEvent(&event));
|
||||
reset_highlight();
|
||||
if (CurrentActiveTextInput >= 0)
|
||||
{
|
||||
auto& cur = _list.at(WINPR_ASSERTING_INT_CAST(size_t, CurrentActiveTextInput));
|
||||
if (!cur.highlight(true))
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!update())
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SdlSelectList::updateInternal()
|
||||
{
|
||||
for (auto& cur : _list)
|
||||
{
|
||||
if (!cur.update())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t SdlSelectList::get_index(const SDL_MouseButtonEvent& button)
|
||||
{
|
||||
const auto x = button.x;
|
||||
const auto y = button.y;
|
||||
for (size_t i = 0; i < _list.size(); i++)
|
||||
{
|
||||
auto& cur = _list.at(i);
|
||||
auto r = cur.rect();
|
||||
|
||||
if ((x >= r.x) && (x <= r.x + r.w) && (y >= r.y) && (y <= r.y + r.h))
|
||||
return WINPR_ASSERTING_INT_CAST(ssize_t, i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SdlSelectList::reset_mouseover()
|
||||
{
|
||||
for (auto& cur : _list)
|
||||
{
|
||||
cur.mouseover(false);
|
||||
}
|
||||
}
|
||||
|
||||
void SdlSelectList::reset_highlight()
|
||||
{
|
||||
for (auto& cur : _list)
|
||||
{
|
||||
cur.highlight(false);
|
||||
}
|
||||
}
|
||||
41
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select_list.hpp
vendored
Normal file
41
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_select_list.hpp
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_widget_list.hpp"
|
||||
#include "sdl_select.hpp"
|
||||
#include "sdl_button.hpp"
|
||||
#include "sdl_buttons.hpp"
|
||||
|
||||
class SdlSelectList : public SdlWidgetList
|
||||
{
|
||||
public:
|
||||
SdlSelectList(const std::string& title, const std::vector<std::string>& labels);
|
||||
SdlSelectList(const SdlSelectList& other) = delete;
|
||||
SdlSelectList(SdlSelectList&& other) = delete;
|
||||
~SdlSelectList() override;
|
||||
|
||||
SdlSelectList& operator=(const SdlSelectList& other) = delete;
|
||||
SdlSelectList& operator=(SdlSelectList&& other) = delete;
|
||||
|
||||
[[nodiscard]] int run();
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool updateInternal() override;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
INPUT_BUTTON_ACCEPT = 0,
|
||||
INPUT_BUTTON_CANCEL = -2
|
||||
};
|
||||
|
||||
ssize_t get_index(const SDL_MouseButtonEvent& button);
|
||||
void reset_mouseover();
|
||||
void reset_highlight();
|
||||
|
||||
std::vector<SdlSelectWidget> _list;
|
||||
};
|
||||
68
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_selectable_widget.cpp
vendored
Normal file
68
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_selectable_widget.cpp
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "sdl_selectable_widget.hpp"
|
||||
#include "sdl_blend_mode_guard.hpp"
|
||||
|
||||
SdlSelectableWidget::SdlSelectableWidget(std::shared_ptr<SDL_Renderer>& renderer,
|
||||
const SDL_FRect& rect)
|
||||
: SdlWidget(renderer, rect)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
SdlSelectableWidget::SdlSelectableWidget(std::shared_ptr<SDL_Renderer>& renderer,
|
||||
const SDL_FRect& rect, SDL_IOStream* ops)
|
||||
: SdlWidget(renderer, rect, ops)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
SdlSelectableWidget::SdlSelectableWidget(SdlSelectableWidget&& other) noexcept = default;
|
||||
|
||||
SdlSelectableWidget::~SdlSelectableWidget() = default;
|
||||
|
||||
bool SdlSelectableWidget::highlight(bool enable)
|
||||
{
|
||||
_highlight = enable;
|
||||
return update();
|
||||
}
|
||||
|
||||
bool SdlSelectableWidget::mouseover(bool enable)
|
||||
{
|
||||
_mouseover = enable;
|
||||
return update();
|
||||
}
|
||||
|
||||
bool SdlSelectableWidget::updateInternal()
|
||||
{
|
||||
SdlBlendModeGuard guard(_renderer, SDL_BLENDMODE_NONE);
|
||||
std::vector<SDL_Color> colors;
|
||||
colors.push_back(_backgroundcolor);
|
||||
if (_highlight)
|
||||
colors.push_back(_highlightcolor);
|
||||
|
||||
if (_mouseover)
|
||||
colors.push_back(_mouseovercolor);
|
||||
|
||||
if (!fill(colors))
|
||||
return false;
|
||||
|
||||
return SdlWidget::updateInternal();
|
||||
}
|
||||
50
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_selectable_widget.hpp
vendored
Normal file
50
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_selectable_widget.hpp
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdl_widget.hpp"
|
||||
|
||||
class SdlSelectableWidget : public SdlWidget
|
||||
{
|
||||
public:
|
||||
SdlSelectableWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect);
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
SdlSelectableWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect,
|
||||
SDL_IOStream* ops);
|
||||
#endif
|
||||
SdlSelectableWidget(SdlSelectableWidget&& other) noexcept;
|
||||
SdlSelectableWidget(const SdlSelectableWidget& other) = delete;
|
||||
~SdlSelectableWidget() override;
|
||||
|
||||
SdlSelectableWidget& operator=(const SdlSelectableWidget& other) = delete;
|
||||
SdlSelectableWidget& operator=(SdlSelectableWidget&& other) = delete;
|
||||
|
||||
bool highlight(bool enable);
|
||||
bool mouseover(bool enable);
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool updateInternal() override;
|
||||
SDL_Color _highlightcolor = { 0xcd, 0xca, 0x35, 0x60 };
|
||||
SDL_Color _mouseovercolor = { 0x66, 0xff, 0x66, 0x60 };
|
||||
|
||||
private:
|
||||
bool _mouseover = false;
|
||||
bool _highlight = false;
|
||||
};
|
||||
332
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget.cpp
vendored
Normal file
332
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget.cpp
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
|
||||
#include "sdl_widget.hpp"
|
||||
#include "sdl_blend_mode_guard.hpp"
|
||||
#include "../sdl_utils.hpp"
|
||||
|
||||
#include "res/sdl3_resource_manager.hpp"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#endif
|
||||
|
||||
#define TAG CLIENT_TAG("SDL.widget")
|
||||
|
||||
static const Uint32 hpadding = 10;
|
||||
|
||||
SdlWidget::SdlWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect)
|
||||
: _renderer(renderer),
|
||||
_engine(TTF_CreateRendererTextEngine(renderer.get()), TTF_DestroyRendererTextEngine),
|
||||
_rect(rect)
|
||||
{
|
||||
assert(renderer);
|
||||
|
||||
auto ops = SDL3ResourceManager::get(SDLResourceManager::typeFonts(),
|
||||
"OpenSans-VariableFont_wdth,wght.ttf");
|
||||
if (!ops)
|
||||
widget_log_error(false, "SDLResourceManager::get");
|
||||
else
|
||||
{
|
||||
_font = std::shared_ptr<TTF_Font>(TTF_OpenFontIO(ops, true, 64), TTF_CloseFont);
|
||||
if (!_font)
|
||||
widget_log_error(false, "TTF_OpenFontRW");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
SdlWidget::SdlWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect,
|
||||
SDL_IOStream* ops)
|
||||
: _renderer(renderer),
|
||||
_engine(TTF_CreateRendererTextEngine(renderer.get()), TTF_DestroySurfaceTextEngine),
|
||||
_rect(rect)
|
||||
{
|
||||
if (ops)
|
||||
{
|
||||
_image = std::shared_ptr<SDL_Texture>(IMG_LoadTexture_IO(renderer.get(), ops, true),
|
||||
SDL_DestroyTexture);
|
||||
if (!_image)
|
||||
widget_log_error(false, "IMG_LoadTexture_IO");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SdlWidget::SdlWidget(SdlWidget&& other) noexcept
|
||||
: _renderer(std::move(other._renderer)), _backgroundcolor(other._backgroundcolor),
|
||||
_fontcolor(other._fontcolor), _text(std::move(other._text)), _font(std::move(other._font)),
|
||||
_image(std::move(other._image)), _engine(std::move(other._engine)), _rect(other._rect),
|
||||
_wrap(other._wrap), _text_width(other._text_width)
|
||||
{
|
||||
other._font = nullptr;
|
||||
other._image = nullptr;
|
||||
other._engine = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SDL_Texture> SdlWidget::render_text(const std::string& text, SDL_Color fgcolor,
|
||||
SDL_FRect& src, SDL_FRect& dst) const
|
||||
{
|
||||
auto surface = std::shared_ptr<SDL_Surface>(
|
||||
TTF_RenderText_Blended(_font.get(), text.c_str(), 0, fgcolor), SDL_DestroySurface);
|
||||
if (!surface)
|
||||
{
|
||||
widget_log_error(false, "TTF_RenderText_Blended");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto texture = std::shared_ptr<SDL_Texture>(
|
||||
SDL_CreateTextureFromSurface(_renderer.get(), surface.get()), SDL_DestroyTexture);
|
||||
if (!texture)
|
||||
{
|
||||
widget_log_error(false, "SDL_CreateTextureFromSurface");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!_engine)
|
||||
{
|
||||
widget_log_error(false, "TTF_CreateRendererTextEngine");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<TTF_Text, decltype(&TTF_DestroyText)> txt(
|
||||
TTF_CreateText(_engine.get(), _font.get(), text.c_str(), text.size()), TTF_DestroyText);
|
||||
|
||||
if (!txt)
|
||||
{
|
||||
widget_log_error(false, "TTF_CreateText");
|
||||
return nullptr;
|
||||
}
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
if (!TTF_GetTextSize(txt.get(), &w, &h))
|
||||
{
|
||||
widget_log_error(false, "TTF_GetTextSize");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
src.w = static_cast<float>(w);
|
||||
src.h = static_cast<float>(h);
|
||||
/* Do some magic:
|
||||
* - Add padding before and after text
|
||||
* - if text is too long only show the last elements
|
||||
* - if text is too short only update used space
|
||||
*/
|
||||
dst = _rect;
|
||||
dst.x += hpadding;
|
||||
dst.w -= 2 * hpadding;
|
||||
const float scale = dst.h / src.h;
|
||||
const float sws = (src.w) * scale;
|
||||
const float dws = (dst.w) / scale;
|
||||
dst.w = std::min(dst.w, sws);
|
||||
if (src.w > dws)
|
||||
{
|
||||
src.x = src.w - dws;
|
||||
src.w = dws;
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
static float scale(float dw, float dh)
|
||||
{
|
||||
const auto scale = dh / dw;
|
||||
const auto dr = dh * scale;
|
||||
return dr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SDL_Texture> SdlWidget::render_text_wrapped(const std::string& text,
|
||||
SDL_Color fgcolor, SDL_FRect& src,
|
||||
SDL_FRect& dst) const
|
||||
{
|
||||
assert(_text_width < INT32_MAX);
|
||||
|
||||
auto surface = std::shared_ptr<SDL_Surface>(
|
||||
TTF_RenderText_Blended_Wrapped(_font.get(), text.c_str(), 0, fgcolor,
|
||||
static_cast<int>(_text_width)),
|
||||
SDL_DestroySurface);
|
||||
if (!surface)
|
||||
{
|
||||
widget_log_error(false, "TTF_RenderText_Blended");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
src.w = static_cast<float>(surface->w);
|
||||
src.h = static_cast<float>(surface->h);
|
||||
|
||||
auto texture = std::shared_ptr<SDL_Texture>(
|
||||
SDL_CreateTextureFromSurface(_renderer.get(), surface.get()), SDL_DestroyTexture);
|
||||
if (!texture)
|
||||
{
|
||||
widget_log_error(false, "SDL_CreateTextureFromSurface");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Do some magic:
|
||||
* - Add padding before and after text
|
||||
* - if text is too long only show the last elements
|
||||
* - if text is too short only update used space
|
||||
*/
|
||||
dst = _rect;
|
||||
dst.x += hpadding;
|
||||
dst.w -= 2 * hpadding;
|
||||
auto dh = scale(src.w, src.h);
|
||||
dst.h = std::min<float>(dh, dst.h);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
SdlWidget::~SdlWidget() = default;
|
||||
|
||||
bool SdlWidget::error_ex(bool success, const char* what, const char* file, size_t line,
|
||||
const char* fkt)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
// Flip SDL3 convention to existing code convention to minimize code changes
|
||||
return false;
|
||||
}
|
||||
static wLog* log = nullptr;
|
||||
if (!log)
|
||||
log = WLog_Get(TAG);
|
||||
// Use -1 as it indicates error similar to SDL2 conventions
|
||||
// sdl_log_error_ex treats any value other than 0 as SDL error
|
||||
return sdl_log_error_ex(-1, log, what, file, line, fkt);
|
||||
}
|
||||
|
||||
bool SdlWidget::updateInternal()
|
||||
{
|
||||
return update_text(_text);
|
||||
}
|
||||
|
||||
bool SdlWidget::draw_rect(const SDL_FRect& rect, SDL_Color color) const
|
||||
{
|
||||
const auto drc = SDL_SetRenderDrawColor(_renderer.get(), color.r, color.g, color.b, color.a);
|
||||
if (widget_log_error(drc, "SDL_SetRenderDrawColor"))
|
||||
return false;
|
||||
|
||||
const auto rc = SDL_RenderFillRect(_renderer.get(), &rect);
|
||||
return !widget_log_error(rc, "SDL_RenderFillRect");
|
||||
}
|
||||
|
||||
bool SdlWidget::fill(SDL_Color color) const
|
||||
{
|
||||
std::vector<SDL_Color> colors = { color };
|
||||
return fill(colors);
|
||||
}
|
||||
|
||||
bool SdlWidget::fill(const std::vector<SDL_Color>& colors) const
|
||||
{
|
||||
SdlBlendModeGuard guard(_renderer, SDL_BLENDMODE_NONE);
|
||||
|
||||
for (auto color : colors)
|
||||
{
|
||||
if (!draw_rect(_rect, color))
|
||||
return false;
|
||||
|
||||
if (!guard.update(SDL_BLENDMODE_ADD))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlWidget::wrap() const
|
||||
{
|
||||
return _wrap;
|
||||
}
|
||||
|
||||
bool SdlWidget::set_wrap(bool wrap, size_t width)
|
||||
{
|
||||
_wrap = wrap;
|
||||
_text_width = width;
|
||||
return _wrap;
|
||||
}
|
||||
|
||||
const SDL_FRect& SdlWidget::rect() const
|
||||
{
|
||||
return _rect;
|
||||
}
|
||||
|
||||
bool SdlWidget::clear() const
|
||||
{
|
||||
if (!_renderer)
|
||||
return false;
|
||||
|
||||
SdlBlendModeGuard guard(_renderer, SDL_BLENDMODE_NONE);
|
||||
|
||||
const auto drc = SDL_SetRenderDrawColor(_renderer.get(), _backgroundcolor.r, _backgroundcolor.g,
|
||||
_backgroundcolor.b, _backgroundcolor.a);
|
||||
if (widget_log_error(drc, "SDL_SetRenderDrawColor"))
|
||||
return false;
|
||||
|
||||
const auto rcls = SDL_RenderRect(_renderer.get(), &_rect);
|
||||
return !widget_log_error(rcls, "SDL_RenderRect");
|
||||
}
|
||||
|
||||
bool SdlWidget::update()
|
||||
{
|
||||
if (!clear())
|
||||
return false;
|
||||
// TODO: Draw widget specifics
|
||||
return updateInternal();
|
||||
}
|
||||
|
||||
bool SdlWidget::update_text(const std::string& text)
|
||||
{
|
||||
_text = text;
|
||||
if (_text.empty())
|
||||
return true;
|
||||
|
||||
SDL_FRect src{};
|
||||
SDL_FRect dst{};
|
||||
|
||||
std::shared_ptr<SDL_Texture> texture;
|
||||
if (_image)
|
||||
{
|
||||
texture = _image;
|
||||
dst = _rect;
|
||||
auto propId = SDL_GetTextureProperties(_image.get());
|
||||
auto w = SDL_GetNumberProperty(propId, SDL_PROP_TEXTURE_WIDTH_NUMBER, -1);
|
||||
auto h = SDL_GetNumberProperty(propId, SDL_PROP_TEXTURE_HEIGHT_NUMBER, -1);
|
||||
if (w < 0 || h < 0)
|
||||
{
|
||||
if (!widget_log_error(false, "SDL_GetTextureProperties"))
|
||||
return false;
|
||||
}
|
||||
src.w = static_cast<float>(w);
|
||||
src.h = static_cast<float>(h);
|
||||
}
|
||||
else if (_wrap)
|
||||
texture = render_text_wrapped(_text, _fontcolor, src, dst);
|
||||
else
|
||||
texture = render_text(_text, _fontcolor, src, dst);
|
||||
if (!texture)
|
||||
return false;
|
||||
|
||||
const auto rc = SDL_RenderTexture(_renderer.get(), texture.get(), &src, &dst);
|
||||
return !widget_log_error(rc, "SDL_RenderCopy");
|
||||
}
|
||||
100
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget.hpp
vendored
Normal file
100
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget.hpp
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client helper dialogs
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
#if !defined(HAS_NOEXCEPT)
|
||||
#if defined(__clang__)
|
||||
#if __has_feature(cxx_noexcept)
|
||||
#define HAS_NOEXCEPT
|
||||
#endif
|
||||
#elif defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
|
||||
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#define HAS_NOEXCEPT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAS_NOEXCEPT
|
||||
#define noexcept
|
||||
#endif
|
||||
|
||||
class SdlWidget
|
||||
{
|
||||
public:
|
||||
SdlWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect);
|
||||
#if defined(WITH_SDL_IMAGE_DIALOGS)
|
||||
SdlWidget(std::shared_ptr<SDL_Renderer>& renderer, const SDL_FRect& rect, SDL_IOStream* ops);
|
||||
#endif
|
||||
SdlWidget(const SdlWidget& other) = delete;
|
||||
SdlWidget(SdlWidget&& other) noexcept;
|
||||
virtual ~SdlWidget();
|
||||
|
||||
SdlWidget& operator=(const SdlWidget& other) = delete;
|
||||
SdlWidget& operator=(SdlWidget&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool fill(SDL_Color color) const;
|
||||
[[nodiscard]] bool fill(const std::vector<SDL_Color>& colors) const;
|
||||
[[nodiscard]] bool update_text(const std::string& text);
|
||||
|
||||
[[nodiscard]] bool wrap() const;
|
||||
[[nodiscard]] bool set_wrap(bool wrap = true, size_t width = 0);
|
||||
[[nodiscard]] const SDL_FRect& rect() const;
|
||||
|
||||
[[nodiscard]] bool update();
|
||||
|
||||
#define widget_log_error(res, what) SdlWidget::error_ex(res, what, __FILE__, __LINE__, __func__)
|
||||
static bool error_ex(bool success, const char* what, const char* file, size_t line,
|
||||
const char* fkt);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<SDL_Renderer> _renderer;
|
||||
SDL_Color _backgroundcolor = { 0x56, 0x56, 0x56, 0xff };
|
||||
SDL_Color _fontcolor = { 0xd1, 0xcf, 0xcd, 0xff };
|
||||
mutable std::string _text;
|
||||
|
||||
virtual bool clear() const;
|
||||
virtual bool updateInternal();
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool draw_rect(const SDL_FRect& rect, SDL_Color color) const;
|
||||
[[nodiscard]] std::shared_ptr<SDL_Texture>
|
||||
render_text(const std::string& text, SDL_Color fgcolor, SDL_FRect& src, SDL_FRect& dst) const;
|
||||
[[nodiscard]] std::shared_ptr<SDL_Texture> render_text_wrapped(const std::string& text,
|
||||
SDL_Color fgcolor,
|
||||
SDL_FRect& src,
|
||||
SDL_FRect& dst) const;
|
||||
|
||||
std::shared_ptr<TTF_Font> _font = nullptr;
|
||||
std::shared_ptr<SDL_Texture> _image = nullptr;
|
||||
std::shared_ptr<TTF_TextEngine> _engine = nullptr;
|
||||
SDL_FRect _rect = {};
|
||||
bool _wrap = false;
|
||||
size_t _text_width = 0;
|
||||
};
|
||||
63
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget_list.cpp
vendored
Normal file
63
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget_list.cpp
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "sdl_widget_list.hpp"
|
||||
#include "sdl_blend_mode_guard.hpp"
|
||||
|
||||
SdlWidgetList::~SdlWidgetList() = default;
|
||||
|
||||
bool SdlWidgetList::reset(const std::string& title, size_t width, size_t height)
|
||||
{
|
||||
auto w = WINPR_ASSERTING_INT_CAST(int, width);
|
||||
auto h = WINPR_ASSERTING_INT_CAST(int, height);
|
||||
SDL_Renderer* renderer = nullptr;
|
||||
SDL_Window* window = nullptr;
|
||||
auto rc = SDL_CreateWindowAndRenderer(
|
||||
title.c_str(), w, h, SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS, &window, &renderer);
|
||||
_renderer = std::shared_ptr<SDL_Renderer>(renderer, SDL_DestroyRenderer);
|
||||
_window = std::shared_ptr<SDL_Window>(window, SDL_DestroyWindow);
|
||||
if (!rc)
|
||||
widget_log_error(rc, "SDL_CreateWindowAndRenderer");
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool SdlWidgetList::visible() const
|
||||
{
|
||||
if (!_window || !_renderer)
|
||||
return false;
|
||||
|
||||
auto flags = SDL_GetWindowFlags(_window.get());
|
||||
return (flags & (SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED)) == 0;
|
||||
}
|
||||
|
||||
bool SdlWidgetList::clearWindow()
|
||||
{
|
||||
if (!_renderer)
|
||||
return false;
|
||||
|
||||
SdlBlendModeGuard guard(_renderer, SDL_BLENDMODE_NONE);
|
||||
const auto drc = SDL_SetRenderDrawColor(_renderer.get(), _backgroundcolor.r, _backgroundcolor.g,
|
||||
_backgroundcolor.b, _backgroundcolor.a);
|
||||
if (widget_log_error(drc, "SDL_SetRenderDrawColor"))
|
||||
return false;
|
||||
|
||||
const auto rcls = SDL_RenderClear(_renderer.get());
|
||||
return !widget_log_error(rcls, "SDL_RenderClear");
|
||||
}
|
||||
|
||||
bool SdlWidgetList::update()
|
||||
{
|
||||
if (!visible())
|
||||
return true;
|
||||
|
||||
if (!clearWindow())
|
||||
return false;
|
||||
if (!updateInternal())
|
||||
return false;
|
||||
if (!_buttons.update())
|
||||
return false;
|
||||
auto rc = SDL_RenderPresent(_renderer.get());
|
||||
if (!rc)
|
||||
{
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] SDL_RenderPresent failed with %s", __func__,
|
||||
SDL_GetError());
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
34
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget_list.hpp
vendored
Normal file
34
third_party/FreeRDP/client/SDL/SDL3/dialogs/sdl_widget_list.hpp
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "sdl_buttons.hpp"
|
||||
|
||||
class SdlWidgetList
|
||||
{
|
||||
public:
|
||||
SdlWidgetList() = default;
|
||||
|
||||
SdlWidgetList(const SdlWidgetList& other) = delete;
|
||||
SdlWidgetList(SdlWidgetList&& other) = delete;
|
||||
SdlWidgetList& operator=(const SdlWidgetList& other) = delete;
|
||||
SdlWidgetList& operator=(SdlWidgetList&& other) = delete;
|
||||
virtual ~SdlWidgetList();
|
||||
|
||||
[[nodiscard]] virtual bool reset(const std::string& title, size_t width, size_t height);
|
||||
|
||||
[[nodiscard]] virtual bool visible() const;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool update();
|
||||
[[nodiscard]] virtual bool clearWindow();
|
||||
[[nodiscard]] virtual bool updateInternal() = 0;
|
||||
|
||||
std::shared_ptr<SDL_Window> _window;
|
||||
std::shared_ptr<SDL_Renderer> _renderer;
|
||||
SdlButtonList _buttons;
|
||||
SDL_Color _backgroundcolor{ 0x38, 0x36, 0x35, 0xff };
|
||||
};
|
||||
5
third_party/FreeRDP/client/SDL/SDL3/dialogs/test/CMakeLists.txt
vendored
Normal file
5
third_party/FreeRDP/client/SDL/SDL3/dialogs/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
set(NAMES "TestSDLDialogInput;TestSDLDialogSelectList")
|
||||
foreach(NAME ${NAMES})
|
||||
add_executable(${NAME} ${NAME}.cpp)
|
||||
target_link_libraries(${NAME} PRIVATE sdl3-dialogs freerdp-client freerdp)
|
||||
endforeach()
|
||||
59
third_party/FreeRDP/client/SDL/SDL3/dialogs/test/TestSDLDialogInput.cpp
vendored
Normal file
59
third_party/FreeRDP/client/SDL/SDL3/dialogs/test/TestSDLDialogInput.cpp
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "../sdl_dialogs.hpp"
|
||||
#include "../sdl_input_widget_pair_list.hpp"
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
typedef int (*fkt_t)(void);
|
||||
|
||||
BOOL sdl_log_error_ex(Sint32 res, wLog* log, const char* what, const char* file, size_t line,
|
||||
const char* fkt)
|
||||
{
|
||||
WINPR_UNUSED(file);
|
||||
|
||||
WLog_Print(log, WLOG_ERROR, "[%s:%" PRIuz "][%s]: %s", fkt, line, what, "xxx");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int auth_dialogs(void)
|
||||
{
|
||||
const std::string title = "sometitle";
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::vector<std::string> initial{ "Smartcard", "abc", "def" };
|
||||
std::vector<Uint32> flags = { SdlInputWidgetPair::SDL_INPUT_READONLY,
|
||||
SdlInputWidgetPair::SDL_INPUT_MASK, 0 };
|
||||
|
||||
const std::vector<std::string>& labels{ "foo", "bar", "gaga" };
|
||||
|
||||
SdlInputWidgetPairList ilist(title.c_str(), labels, initial, flags);
|
||||
auto rc = ilist.run(result);
|
||||
|
||||
if ((result.size() < labels.size()))
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int runTest(fkt_t fkt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
sdl_dialogs_init();
|
||||
try
|
||||
{
|
||||
rc = fkt();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
rc = e;
|
||||
}
|
||||
sdl_dialogs_uninit();
|
||||
SDL_Quit();
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
|
||||
{
|
||||
return runTest(auth_dialogs);
|
||||
}
|
||||
47
third_party/FreeRDP/client/SDL/SDL3/dialogs/test/TestSDLDialogSelectList.cpp
vendored
Normal file
47
third_party/FreeRDP/client/SDL/SDL3/dialogs/test/TestSDLDialogSelectList.cpp
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "../sdl_dialogs.hpp"
|
||||
#include "../sdl_select_list.hpp"
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
typedef int (*fkt_t)(void);
|
||||
|
||||
BOOL sdl_log_error_ex(Sint32 res, wLog* log, const char* what, const char* file, size_t line,
|
||||
const char* fkt)
|
||||
{
|
||||
WINPR_UNUSED(file);
|
||||
|
||||
WLog_Print(log, WLOG_ERROR, "[%s:%" PRIuz "][%s]: %s", fkt, line, what, "xxx");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int select_dialogs(void)
|
||||
{
|
||||
const std::vector<std::string> labels{ "foo", "bar", "gaga", "blabla" };
|
||||
SdlSelectList list{ "title", labels };
|
||||
return list.run();
|
||||
}
|
||||
|
||||
static int runTest(fkt_t fkt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
sdl_dialogs_init();
|
||||
try
|
||||
{
|
||||
rc = fkt();
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
rc = e;
|
||||
}
|
||||
sdl_dialogs_uninit();
|
||||
SDL_Quit();
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
|
||||
{
|
||||
return runTest(select_dialogs);
|
||||
}
|
||||
15
third_party/FreeRDP/client/SDL/SDL3/man/CMakeLists.txt
vendored
Normal file
15
third_party/FreeRDP/client/SDL/SDL3/man/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
set(DEPS
|
||||
../../../common/man/freerdp-global-options.1
|
||||
../../../common/man/freerdp-global-envvar.1
|
||||
../../common/man/sdl-freerdp-config.1
|
||||
../../../common/man/freerdp-global-config.1
|
||||
../../common/man/sdl-global-config.1
|
||||
../../common/man/sdl-freerdp-examples.1
|
||||
../../../common/man/freerdp-global-links.1
|
||||
)
|
||||
|
||||
include(GetSysconfDir)
|
||||
get_sysconf_dir("" SYSCONF_DIR)
|
||||
set(SDL_WIKI_BASE_URL "https://wiki.libsdl.org/SDL3")
|
||||
set(VAR_NAMES "VENDOR" "PRODUCT" "VENDOR_PRODUCT" "SYSCONF_DIR" "SDL_WIKI_BASE_URL")
|
||||
generate_and_install_freerdp_man_from_xml(${MODULE_NAME} "1" "${DEPS}" "${VAR_NAMES}")
|
||||
15
third_party/FreeRDP/client/SDL/SDL3/man/sdl3-freerdp.1.in
vendored
Normal file
15
third_party/FreeRDP/client/SDL/SDL3/man/sdl3-freerdp.1.in
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
.TH "@MANPAGE_NAME@" "1" "@MAN_TODAY@" "freerdp" "@MANPAGE_NAME@"
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.SH "NAME"
|
||||
@MANPAGE_NAME@ \- FreeRDP SDL client
|
||||
.SH "SYNOPSIS"
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@\fR
|
||||
[file] [options] [/v:server[:port]]
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fB@MANPAGE_NAME@\fR
|
||||
is an SDL Remote Desktop Protocol (RDP) client which is part of the FreeRDP project\&. An RDP server is built\-in to many editions of Windows\&. Alternative servers included ogon, gnome\-remote\-desktop, xrdp and VRDP (VirtualBox)\&.
|
||||
93
third_party/FreeRDP/client/SDL/SDL3/sdl_channels.cpp
vendored
Normal file
93
third_party/FreeRDP/client/SDL/SDL3/sdl_channels.cpp
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client Channels
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/client/rail.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
|
||||
#include "sdl_channels.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
#include "sdl_disp.hpp"
|
||||
|
||||
void sdl_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e)
|
||||
{
|
||||
auto sdl = get_context(context);
|
||||
|
||||
WINPR_ASSERT(sdl);
|
||||
WINPR_ASSERT(e);
|
||||
|
||||
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
auto clip = reinterpret_cast<CliprdrClientContext*>(e->pInterface);
|
||||
WINPR_ASSERT(clip);
|
||||
|
||||
if (!sdl->getClipboardChannelContext().init(clip))
|
||||
WLog_Print(sdl->getWLog(), WLOG_WARN, "Failed to initialize clipboard channel");
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
auto disp = reinterpret_cast<DispClientContext*>(e->pInterface);
|
||||
WINPR_ASSERT(disp);
|
||||
|
||||
if (!sdl->getDisplayChannelContext().init(disp))
|
||||
WLog_Print(sdl->getWLog(), WLOG_WARN, "Failed to initialize display channel");
|
||||
}
|
||||
else
|
||||
freerdp_client_OnChannelConnectedEventHandler(context, e);
|
||||
}
|
||||
|
||||
void sdl_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
auto sdl = get_context(context);
|
||||
|
||||
WINPR_ASSERT(sdl);
|
||||
WINPR_ASSERT(e);
|
||||
|
||||
// TODO: Set resizeable depending on disp channel and /dynamic-resolution
|
||||
if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
auto clip = reinterpret_cast<CliprdrClientContext*>(e->pInterface);
|
||||
WINPR_ASSERT(clip);
|
||||
|
||||
if (!sdl->getClipboardChannelContext().uninit(clip))
|
||||
WLog_Print(sdl->getWLog(), WLOG_WARN, "Failed to uninitialize clipboard channel");
|
||||
clip->custom = nullptr;
|
||||
}
|
||||
else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
auto disp = reinterpret_cast<DispClientContext*>(e->pInterface);
|
||||
WINPR_ASSERT(disp);
|
||||
|
||||
if (!sdl->getDisplayChannelContext().uninit(disp))
|
||||
WLog_Print(sdl->getWLog(), WLOG_WARN, "Failed to uninitialize display channel");
|
||||
disp->custom = nullptr;
|
||||
}
|
||||
else
|
||||
freerdp_client_OnChannelDisconnectedEventHandler(context, e);
|
||||
}
|
||||
26
third_party/FreeRDP/client/SDL/SDL3/sdl_channels.hpp
vendored
Normal file
26
third_party/FreeRDP/client/SDL/SDL3/sdl_channels.hpp
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client Channels
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
|
||||
void sdl_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e);
|
||||
void sdl_OnChannelDisconnectedEventHandler(void* context, const ChannelDisconnectedEventArgs* e);
|
||||
1008
third_party/FreeRDP/client/SDL/SDL3/sdl_clip.cpp
vendored
Normal file
1008
third_party/FreeRDP/client/SDL/SDL3/sdl_clip.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
160
third_party/FreeRDP/client/SDL/SDL3/sdl_clip.hpp
vendored
Normal file
160
third_party/FreeRDP/client/SDL/SDL3/sdl_clip.hpp
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client keyboard helper
|
||||
*
|
||||
* Copyright 2024 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2024 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/client_cliprdr_file.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_types.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
/** @brief a clipboard format request */
|
||||
class ClipRequest
|
||||
{
|
||||
public:
|
||||
ClipRequest(UINT32 format, const std::string& mime);
|
||||
ClipRequest(const ClipRequest& other) = default;
|
||||
ClipRequest(ClipRequest&& other) = default;
|
||||
~ClipRequest() = default;
|
||||
|
||||
ClipRequest& operator=(const ClipRequest& other) = delete;
|
||||
ClipRequest& operator=(ClipRequest&& other) = delete;
|
||||
|
||||
[[nodiscard]] uint32_t format() const;
|
||||
[[nodiscard]] std::string formatstr() const;
|
||||
[[nodiscard]] std::string mime() const;
|
||||
[[nodiscard]] bool success() const;
|
||||
void setSuccess(bool status);
|
||||
|
||||
private:
|
||||
uint32_t _format;
|
||||
std::string _mime;
|
||||
bool _success;
|
||||
};
|
||||
|
||||
class CliprdrFormat
|
||||
{
|
||||
public:
|
||||
CliprdrFormat(uint32_t formatID, const char* formatName);
|
||||
|
||||
[[nodiscard]] uint32_t formatId() const;
|
||||
[[nodiscard]] const char* formatName() const;
|
||||
|
||||
private:
|
||||
uint32_t _formatID;
|
||||
std::string _formatName;
|
||||
};
|
||||
|
||||
/** @brief object that handles clipboard context for the SDL3 client */
|
||||
class sdlClip
|
||||
{
|
||||
public:
|
||||
explicit sdlClip(SdlContext* sdl);
|
||||
virtual ~sdlClip();
|
||||
|
||||
sdlClip(const sdlClip&) = delete;
|
||||
sdlClip(sdlClip&&) = delete;
|
||||
|
||||
sdlClip& operator=(const sdlClip&) = delete;
|
||||
sdlClip& operator=(sdlClip&&) = delete;
|
||||
|
||||
[[nodiscard]] bool init(CliprdrClientContext* clip);
|
||||
[[nodiscard]] bool uninit(CliprdrClientContext* clip);
|
||||
|
||||
[[nodiscard]] bool handleEvent(const SDL_ClipboardEvent& ev);
|
||||
|
||||
private:
|
||||
[[nodiscard]] UINT SendClientCapabilities();
|
||||
void clearServerFormats();
|
||||
[[nodiscard]] UINT SendFormatListResponse(BOOL status);
|
||||
[[nodiscard]] UINT SendDataResponse(const BYTE* data, size_t size);
|
||||
[[nodiscard]] UINT SendDataRequest(uint32_t formatID, const std::string& mime);
|
||||
|
||||
[[nodiscard]] std::string getServerFormat(uint32_t id);
|
||||
[[nodiscard]] uint32_t serverIdForMime(const std::string& mime);
|
||||
|
||||
[[nodiscard]] bool contains(const char** mime_types, Sint32 count);
|
||||
|
||||
[[nodiscard]] static UINT MonitorReady(CliprdrClientContext* context,
|
||||
const CLIPRDR_MONITOR_READY* monitorReady);
|
||||
|
||||
[[nodiscard]] static UINT ReceiveServerCapabilities(CliprdrClientContext* context,
|
||||
const CLIPRDR_CAPABILITIES* capabilities);
|
||||
[[nodiscard]] static UINT ReceiveServerFormatList(CliprdrClientContext* context,
|
||||
const CLIPRDR_FORMAT_LIST* formatList);
|
||||
[[nodiscard]] static UINT
|
||||
ReceiveFormatListResponse(CliprdrClientContext* context,
|
||||
const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse);
|
||||
[[nodiscard]] static std::shared_ptr<BYTE> ReceiveFormatDataRequestHandle(
|
||||
sdlClip* clipboard, const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest, uint32_t& len);
|
||||
[[nodiscard]] static UINT
|
||||
ReceiveFormatDataRequest(CliprdrClientContext* context,
|
||||
const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest);
|
||||
[[nodiscard]] static UINT
|
||||
ReceiveFormatDataResponse(CliprdrClientContext* context,
|
||||
const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse);
|
||||
|
||||
[[nodiscard]] static const void* SDLCALL ClipDataCb(void* userdata, const char* mime_type,
|
||||
size_t* size);
|
||||
static void SDLCALL ClipCleanCb(void* userdata);
|
||||
|
||||
[[nodiscard]] static bool mime_is_file(const std::string& mime);
|
||||
[[nodiscard]] static bool mime_is_text(const std::string& mime);
|
||||
[[nodiscard]] static bool mime_is_image(const std::string& mime);
|
||||
[[nodiscard]] static bool mime_is_bmp(const std::string& mime);
|
||||
[[nodiscard]] static bool mime_is_html(const std::string& mime);
|
||||
|
||||
SdlContext* _sdl = nullptr;
|
||||
CliprdrFileContext* _file = nullptr;
|
||||
CliprdrClientContext* _ctx = nullptr;
|
||||
wLog* _log = nullptr;
|
||||
wClipboard* _system = nullptr;
|
||||
std::atomic<bool> _sync = false;
|
||||
HANDLE _event = nullptr;
|
||||
Uint64 _last_timestamp = 0;
|
||||
|
||||
std::vector<CliprdrFormat> _serverFormats;
|
||||
CriticalSection _lock;
|
||||
|
||||
std::queue<ClipRequest> _request_queue;
|
||||
|
||||
struct cache_entry
|
||||
{
|
||||
cache_entry(size_t len, std::shared_ptr<void> p) : size(len), ptr(std::move(p))
|
||||
{
|
||||
}
|
||||
|
||||
size_t size;
|
||||
std::shared_ptr<void> ptr;
|
||||
};
|
||||
std::map<std::string, cache_entry> _cache_data;
|
||||
std::vector<const char*> _current_mimetypes;
|
||||
std::string _uuid;
|
||||
std::string _mime_uuid;
|
||||
};
|
||||
30
third_party/FreeRDP/client/SDL/SDL3/sdl_config.hpp.in
vendored
Normal file
30
third_party/FreeRDP/client/SDL/SDL3/sdl_config.hpp.in
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL config template
|
||||
*
|
||||
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2025 Thinast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#cmakedefine WITH_WEBVIEW
|
||||
|
||||
static const char SDL_CLIENT_NAME[] = "@SDL_CLIENT_BINARY_NAME@";
|
||||
static const char SDL_CLIENT_VERSION[] = "@FREERDP_VERSION_FULL@ (@GIT_REVISION@)";
|
||||
static const char SDL_CLIENT_VENDOR[] = "@VENDOR@";
|
||||
static const char SDL_CLIENT_UUID[] = "@SDL_CLIENT_UUID@";
|
||||
static const char SDL_CLIENT_COPYRIGHT[] = "FreeRDP project";
|
||||
static const char SDL_CLIENT_URL[] = "@PROJECT_URL@";
|
||||
static const char SDL_CLIENT_TYPE[] = "application";
|
||||
1651
third_party/FreeRDP/client/SDL/SDL3/sdl_context.cpp
vendored
Normal file
1651
third_party/FreeRDP/client/SDL/SDL3/sdl_context.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
229
third_party/FreeRDP/client/SDL/SDL3/sdl_context.hpp
vendored
Normal file
229
third_party/FreeRDP/client/SDL/SDL3/sdl_context.hpp
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <sdl_common_utils.hpp>
|
||||
|
||||
#include "sdl_window.hpp"
|
||||
#include "sdl_disp.hpp"
|
||||
#include "sdl_clip.hpp"
|
||||
#include "sdl_input.hpp"
|
||||
|
||||
#include "dialogs/sdl_connection_dialog_wrapper.hpp"
|
||||
|
||||
class SdlContext
|
||||
{
|
||||
public:
|
||||
enum CursorType
|
||||
{
|
||||
CURSOR_NULL,
|
||||
CURSOR_DEFAULT,
|
||||
CURSOR_IMAGE
|
||||
};
|
||||
|
||||
explicit SdlContext(rdpContext* context);
|
||||
SdlContext(const SdlContext& other) = delete;
|
||||
SdlContext(SdlContext&& other) = delete;
|
||||
~SdlContext() = default;
|
||||
|
||||
SdlContext& operator=(const SdlContext& other) = delete;
|
||||
SdlContext& operator=(SdlContext&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool redraw(bool suppress = false) const;
|
||||
|
||||
void setConnected(bool val);
|
||||
[[nodiscard]] bool isConnected() const;
|
||||
void cleanup();
|
||||
|
||||
[[nodiscard]] bool resizeable() const;
|
||||
[[nodiscard]] bool toggleResizeable();
|
||||
[[nodiscard]] bool setResizeable(bool enable);
|
||||
|
||||
[[nodiscard]] bool fullscreen() const;
|
||||
[[nodiscard]] bool toggleFullscreen();
|
||||
[[nodiscard]] bool setFullscreen(bool enter, bool forceOriginalDisplay = false);
|
||||
|
||||
[[nodiscard]] bool setMinimized();
|
||||
|
||||
[[nodiscard]] bool grabMouse() const;
|
||||
[[nodiscard]] bool toggleGrabMouse();
|
||||
[[nodiscard]] bool setGrabMouse(bool enter);
|
||||
|
||||
[[nodiscard]] bool grabKeyboard() const;
|
||||
[[nodiscard]] bool toggleGrabKeyboard();
|
||||
[[nodiscard]] bool setGrabKeyboard(bool enter);
|
||||
|
||||
[[nodiscard]] rdpContext* context() const;
|
||||
[[nodiscard]] rdpClientContext* common() const;
|
||||
|
||||
[[nodiscard]] bool setCursor(CursorType type);
|
||||
[[nodiscard]] bool setCursor(rdpPointer* cursor);
|
||||
[[nodiscard]] rdpPointer* cursor() const;
|
||||
[[nodiscard]] bool restoreCursor();
|
||||
|
||||
void setMonitorIds(const std::vector<SDL_DisplayID>& ids);
|
||||
[[nodiscard]] const std::vector<SDL_DisplayID>& monitorIds() const;
|
||||
[[nodiscard]] int64_t monitorId(uint32_t index) const;
|
||||
|
||||
void push(std::vector<SDL_Rect>&& rects);
|
||||
[[nodiscard]] std::vector<SDL_Rect> pop();
|
||||
|
||||
void setHasCursor(bool val);
|
||||
[[nodiscard]] bool hasCursor() const;
|
||||
|
||||
void setMetadata();
|
||||
|
||||
[[nodiscard]] int start();
|
||||
[[nodiscard]] int join();
|
||||
[[nodiscard]] bool shallAbort(bool ignoreDialogs = false);
|
||||
|
||||
[[nodiscard]] bool createWindows();
|
||||
[[nodiscard]] bool updateWindowList();
|
||||
[[nodiscard]] bool updateWindow(SDL_WindowID id);
|
||||
|
||||
[[nodiscard]] bool drawToWindows(const std::vector<SDL_Rect>& rects = {});
|
||||
[[nodiscard]] bool drawToWindow(SdlWindow& window, const std::vector<SDL_Rect>& rects = {});
|
||||
[[nodiscard]] bool minimizeAllWindows();
|
||||
[[nodiscard]] int exitCode() const;
|
||||
[[nodiscard]] SDL_PixelFormat pixelFormat() const;
|
||||
|
||||
[[nodiscard]] const SdlWindow* getWindowForId(SDL_WindowID id) const;
|
||||
[[nodiscard]] SdlWindow* getWindowForId(SDL_WindowID id);
|
||||
[[nodiscard]] SdlWindow* getFirstWindow();
|
||||
|
||||
[[nodiscard]] bool addDisplayWindow(SDL_DisplayID id);
|
||||
[[nodiscard]] bool removeDisplayWindow(SDL_DisplayID id);
|
||||
[[nodiscard]] bool detectDisplays();
|
||||
[[nodiscard]] rdpMonitor getDisplay(SDL_DisplayID id) const;
|
||||
[[nodiscard]] std::vector<SDL_DisplayID> getDisplayIds() const;
|
||||
|
||||
[[nodiscard]] sdlDispContext& getDisplayChannelContext();
|
||||
[[nodiscard]] sdlInput& getInputChannelContext();
|
||||
[[nodiscard]] sdlClip& getClipboardChannelContext();
|
||||
|
||||
[[nodiscard]] SdlConnectionDialogWrapper& getDialog();
|
||||
|
||||
[[nodiscard]] wLog* getWLog();
|
||||
|
||||
[[nodiscard]] bool moveMouseTo(const SDL_FPoint& pos);
|
||||
|
||||
[[nodiscard]] SDL_FPoint screenToPixel(SDL_WindowID id, const SDL_FPoint& pos);
|
||||
|
||||
[[nodiscard]] SDL_FPoint pixelToScreen(SDL_WindowID id, const SDL_FPoint& pos);
|
||||
[[nodiscard]] SDL_FRect pixelToScreen(SDL_WindowID id, const SDL_FRect& pos);
|
||||
|
||||
[[nodiscard]] bool handleEvent(const SDL_Event& ev);
|
||||
|
||||
private:
|
||||
[[nodiscard]] static BOOL preConnect(freerdp* instance);
|
||||
[[nodiscard]] static BOOL postConnect(freerdp* instance);
|
||||
static void postDisconnect(freerdp* instance);
|
||||
static void postFinalDisconnect(freerdp* instance);
|
||||
[[nodiscard]] static BOOL desktopResize(rdpContext* context);
|
||||
[[nodiscard]] static BOOL playSound(rdpContext* context, const PLAY_SOUND_UPDATE* play_sound);
|
||||
[[nodiscard]] static BOOL beginPaint(rdpContext* context);
|
||||
[[nodiscard]] static BOOL endPaint(rdpContext* context);
|
||||
[[nodiscard]] static DWORD WINAPI rdpThreadRun(SdlContext* sdl);
|
||||
|
||||
[[nodiscard]] bool eventToPixelCoordinates(SDL_WindowID id, SDL_Event& ev);
|
||||
|
||||
[[nodiscard]] SDL_FPoint applyLocalScaling(const SDL_FPoint& val) const;
|
||||
void removeLocalScaling(float& x, float& y) const;
|
||||
|
||||
[[nodiscard]] bool handleEvent(const SDL_WindowEvent& ev);
|
||||
[[nodiscard]] bool handleEvent(const SDL_DisplayEvent& ev);
|
||||
[[nodiscard]] bool handleEvent(const SDL_MouseButtonEvent& ev);
|
||||
[[nodiscard]] bool handleEvent(const SDL_MouseMotionEvent& ev);
|
||||
[[nodiscard]] bool handleEvent(const SDL_MouseWheelEvent& ev);
|
||||
[[nodiscard]] bool handleEvent(const SDL_TouchFingerEvent& ev);
|
||||
|
||||
void addOrUpdateDisplay(SDL_DisplayID id);
|
||||
void deleteDisplay(SDL_DisplayID id);
|
||||
|
||||
[[nodiscard]] bool createPrimary();
|
||||
[[nodiscard]] std::string windowTitle() const;
|
||||
[[nodiscard]] bool waitForWindowsCreated();
|
||||
|
||||
void sdl_client_cleanup(int exit_code, const std::string& error_msg);
|
||||
[[nodiscard]] int sdl_client_thread_connect(std::string& error_msg);
|
||||
[[nodiscard]] int sdl_client_thread_run(std::string& error_msg);
|
||||
|
||||
[[nodiscard]] int error_info_to_error(DWORD* pcode, char** msg, size_t* len) const;
|
||||
|
||||
void applyMonitorOffset(SDL_WindowID window, float& x, float& y) const;
|
||||
|
||||
[[nodiscard]] std::vector<SDL_DisplayID>
|
||||
updateDisplayOffsetsForNeighbours(SDL_DisplayID id,
|
||||
const std::vector<SDL_DisplayID>& ignore = {});
|
||||
void updateMonitorDataFromOffsets();
|
||||
|
||||
rdpContext* _context = nullptr;
|
||||
wLog* _log = nullptr;
|
||||
|
||||
std::atomic<bool> _connected = false;
|
||||
bool _cursor_visible = true;
|
||||
rdpPointer* _cursor = nullptr;
|
||||
CursorType _cursorType = CURSOR_NULL;
|
||||
std::vector<SDL_DisplayID> _monitorIds;
|
||||
std::mutex _queue_mux;
|
||||
std::queue<std::vector<SDL_Rect>> _queue;
|
||||
/* SDL */
|
||||
bool _fullscreen = false;
|
||||
bool _resizeable = false;
|
||||
bool _grabMouse = false;
|
||||
bool _grabKeyboard = false;
|
||||
int _exitCode = -1;
|
||||
std::atomic<bool> _rdpThreadRunning = false;
|
||||
SDL_PixelFormat _sdlPixelFormat = SDL_PIXELFORMAT_UNKNOWN;
|
||||
|
||||
CriticalSection _critical;
|
||||
|
||||
using SDLSurfacePtr = std::unique_ptr<SDL_Surface, decltype(&SDL_DestroySurface)>;
|
||||
|
||||
SDLSurfacePtr _primary;
|
||||
SDL_FPoint _localScale{ 1.0f, 1.0f };
|
||||
|
||||
sdlDispContext _disp;
|
||||
sdlInput _input;
|
||||
sdlClip _clip;
|
||||
|
||||
SdlConnectionDialogWrapper _dialog;
|
||||
|
||||
std::map<SDL_DisplayID, rdpMonitor> _displays;
|
||||
std::map<SDL_WindowID, SdlWindow> _windows;
|
||||
std::map<SDL_DisplayID, std::pair<SDL_Rect, SDL_Rect>> _offsets;
|
||||
|
||||
uint32_t _windowWidth = 0;
|
||||
uint32_t _windowHeigth = 0;
|
||||
WinPREvent _windowsCreatedEvent;
|
||||
std::thread _thread;
|
||||
};
|
||||
488
third_party/FreeRDP/client/SDL/SDL3/sdl_disp.cpp
vendored
Normal file
488
third_party/FreeRDP/client/SDL/SDL3/sdl_disp.cpp
vendored
Normal file
@@ -0,0 +1,488 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Display Control Channel
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_disp.hpp"
|
||||
#include "sdl_input.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG CLIENT_TAG("sdl.disp")
|
||||
|
||||
static constexpr UINT64 RESIZE_MIN_DELAY = 200; /* minimum delay in ms between two resizes */
|
||||
static constexpr unsigned MAX_RETRIES = 5;
|
||||
|
||||
static auto operator==(const DISPLAY_CONTROL_MONITOR_LAYOUT& a,
|
||||
const DISPLAY_CONTROL_MONITOR_LAYOUT& b)
|
||||
{
|
||||
if (a.Flags != b.Flags)
|
||||
return false;
|
||||
if (a.Left != b.Left)
|
||||
return false;
|
||||
if (a.Top != b.Top)
|
||||
return false;
|
||||
if (a.Width != b.Width)
|
||||
return false;
|
||||
if (a.Height != b.Height)
|
||||
return false;
|
||||
if (a.PhysicalWidth != b.PhysicalWidth)
|
||||
return false;
|
||||
if (a.PhysicalHeight != b.PhysicalHeight)
|
||||
return false;
|
||||
if (a.Orientation != b.Orientation)
|
||||
return false;
|
||||
if (a.DesktopScaleFactor != b.DesktopScaleFactor)
|
||||
return false;
|
||||
if (a.DeviceScaleFactor != b.DeviceScaleFactor)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdlDispContext::settings_changed(const std::vector<DISPLAY_CONTROL_MONITOR_LAYOUT>& layout)
|
||||
{
|
||||
return (layout != _last_sent_layout);
|
||||
}
|
||||
|
||||
bool sdlDispContext::sendResize()
|
||||
{
|
||||
auto settings = _sdl->context()->settings;
|
||||
|
||||
if (!settings)
|
||||
return false;
|
||||
|
||||
if (!_activated || !_disp)
|
||||
return true;
|
||||
|
||||
if (GetTickCount64() - _lastSentDate < RESIZE_MIN_DELAY)
|
||||
return true;
|
||||
|
||||
_lastSentDate = GetTickCount64();
|
||||
|
||||
const UINT32 mcount = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
|
||||
auto monitors = static_cast<const rdpMonitor*>(
|
||||
freerdp_settings_get_pointer(settings, FreeRDP_MonitorDefArray));
|
||||
return sendLayout(monitors, mcount);
|
||||
}
|
||||
|
||||
bool sdlDispContext::setWindowResizeable()
|
||||
{
|
||||
return _sdl->setResizeable(true);
|
||||
}
|
||||
|
||||
static bool sdl_disp_check_context(void* context, SdlContext** ppsdl, sdlDispContext** ppsdlDisp,
|
||||
rdpSettings** ppSettings)
|
||||
{
|
||||
if (!context)
|
||||
return false;
|
||||
|
||||
auto sdl = get_context(context);
|
||||
if (!sdl)
|
||||
return false;
|
||||
|
||||
if (!sdl->context()->settings)
|
||||
return false;
|
||||
|
||||
*ppsdl = sdl;
|
||||
*ppsdlDisp = &sdl->getDisplayChannelContext();
|
||||
*ppSettings = sdl->context()->settings;
|
||||
return true;
|
||||
}
|
||||
|
||||
void sdlDispContext::OnActivated(void* context, const ActivatedEventArgs* e)
|
||||
{
|
||||
SdlContext* sdl = nullptr;
|
||||
sdlDispContext* sdlDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
|
||||
return;
|
||||
|
||||
sdlDisp->_waitingResize = false;
|
||||
|
||||
if (sdlDisp->_activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
if (!sdlDisp->setWindowResizeable())
|
||||
return;
|
||||
|
||||
if (e->firstActivation)
|
||||
return;
|
||||
|
||||
std::ignore = sdlDisp->addTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void sdlDispContext::OnGraphicsReset(void* context, const GraphicsResetEventArgs* e)
|
||||
{
|
||||
SdlContext* sdl = nullptr;
|
||||
sdlDispContext* sdlDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_UNUSED(e);
|
||||
if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
|
||||
return;
|
||||
|
||||
sdlDisp->_waitingResize = false;
|
||||
|
||||
if (sdlDisp->_activated && !freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
if (sdlDisp->setWindowResizeable())
|
||||
std::ignore = sdlDisp->addTimer();
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 sdlDispContext::OnTimer(void* param, [[maybe_unused]] SDL_TimerID timerID, Uint32 interval)
|
||||
{
|
||||
auto ctx = static_cast<sdlDispContext*>(param);
|
||||
if (!ctx)
|
||||
return 0;
|
||||
|
||||
SdlContext* sdl = ctx->_sdl;
|
||||
if (!sdl)
|
||||
return 0;
|
||||
|
||||
sdlDispContext* sdlDisp = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
if (!sdl_disp_check_context(sdl->context(), &sdl, &sdlDisp, &settings))
|
||||
return 0;
|
||||
|
||||
WLog_Print(sdl->getWLog(), WLOG_TRACE, "checking for display changes...");
|
||||
|
||||
auto rc = sdlDisp->sendResize();
|
||||
if (!rc)
|
||||
WLog_Print(sdl->getWLog(), WLOG_TRACE, "sent new display layout, result %d", rc);
|
||||
|
||||
if (sdlDisp->_timer_retries++ >= MAX_RETRIES)
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_TRACE, "deactivate timer, retries exceeded");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WLog_Print(sdl->getWLog(), WLOG_TRACE, "fire timer one more time");
|
||||
return interval;
|
||||
}
|
||||
|
||||
bool sdlDispContext::sendLayout(const rdpMonitor* monitors, size_t nmonitors)
|
||||
{
|
||||
WINPR_ASSERT(monitors);
|
||||
WINPR_ASSERT(nmonitors > 0);
|
||||
|
||||
auto settings = _sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
std::vector<DISPLAY_CONTROL_MONITOR_LAYOUT> layouts;
|
||||
layouts.reserve(nmonitors);
|
||||
|
||||
for (size_t i = 0; i < nmonitors; i++)
|
||||
{
|
||||
auto monitor = &monitors[i];
|
||||
DISPLAY_CONTROL_MONITOR_LAYOUT layout = {};
|
||||
|
||||
layout.Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
|
||||
layout.Left = monitor->x;
|
||||
layout.Top = monitor->y;
|
||||
layout.Width = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
|
||||
layout.Height = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
|
||||
layout.Orientation = ORIENTATION_LANDSCAPE;
|
||||
layout.PhysicalWidth = monitor->attributes.physicalWidth;
|
||||
layout.PhysicalHeight = monitor->attributes.physicalHeight;
|
||||
|
||||
switch (monitor->attributes.orientation)
|
||||
{
|
||||
case ORIENTATION_PORTRAIT:
|
||||
layout.Orientation = ORIENTATION_PORTRAIT;
|
||||
break;
|
||||
|
||||
case ORIENTATION_LANDSCAPE_FLIPPED:
|
||||
layout.Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
break;
|
||||
|
||||
case ORIENTATION_PORTRAIT_FLIPPED:
|
||||
layout.Orientation = ORIENTATION_PORTRAIT_FLIPPED;
|
||||
break;
|
||||
|
||||
case ORIENTATION_LANDSCAPE:
|
||||
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
|
||||
*/
|
||||
layout.Orientation = ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
}
|
||||
|
||||
layout.DesktopScaleFactor = monitor->attributes.desktopScaleFactor;
|
||||
layout.DeviceScaleFactor = monitor->attributes.deviceScaleFactor;
|
||||
|
||||
auto mask = freerdp_settings_get_uint64(settings, FreeRDP_MonitorOverrideFlags);
|
||||
if ((mask & FREERDP_MONITOR_OVERRIDE_ORIENTATION) != 0)
|
||||
layout.Orientation = freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
|
||||
if ((mask & FREERDP_MONITOR_OVERRIDE_DESKTOP_SCALE) != 0)
|
||||
layout.DesktopScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
|
||||
if ((mask & FREERDP_MONITOR_OVERRIDE_DEVICE_SCALE) != 0)
|
||||
layout.DeviceScaleFactor =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
|
||||
layouts.emplace_back(layout);
|
||||
}
|
||||
|
||||
if (!settings_changed(layouts))
|
||||
return true;
|
||||
|
||||
WINPR_ASSERT(_disp);
|
||||
const size_t len = layouts.size();
|
||||
WINPR_ASSERT(len <= UINT32_MAX);
|
||||
const auto ret = IFCALLRESULT(CHANNEL_RC_OK, _disp->SendMonitorLayout, _disp,
|
||||
static_cast<UINT32>(len), layouts.data());
|
||||
if (ret != CHANNEL_RC_OK)
|
||||
return false;
|
||||
_last_sent_layout = layouts;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdlDispContext::addTimer()
|
||||
{
|
||||
if (SDL_WasInit(SDL_INIT_EVENTS) == 0)
|
||||
return false;
|
||||
|
||||
SDL_RemoveTimer(_timer);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_TRACE, "adding new display check timer");
|
||||
|
||||
_timer_retries = 0;
|
||||
if (!sendResize())
|
||||
return false;
|
||||
_timer = SDL_AddTimer(1000, sdlDispContext::OnTimer, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdlDispContext::updateMonitor(SDL_WindowID id)
|
||||
{
|
||||
if (!freerdp_settings_get_bool(_sdl->context()->settings, FreeRDP_DynamicResolutionUpdate))
|
||||
return true;
|
||||
|
||||
if (!_sdl->updateWindow(id))
|
||||
return false;
|
||||
|
||||
if (!_sdl->updateWindowList())
|
||||
return false;
|
||||
|
||||
return addTimer();
|
||||
}
|
||||
|
||||
bool sdlDispContext::updateMonitors(SDL_EventType type, SDL_DisplayID displayID)
|
||||
{
|
||||
auto settings = _sdl->context()->settings;
|
||||
if (!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon))
|
||||
return true;
|
||||
|
||||
if (!freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
|
||||
return true;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SDL_EVENT_DISPLAY_ADDED:
|
||||
if (!_sdl->addDisplayWindow(displayID))
|
||||
return false;
|
||||
break;
|
||||
case SDL_EVENT_DISPLAY_REMOVED:
|
||||
if (!_sdl->removeDisplayWindow(displayID))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_sdl->updateWindowList())
|
||||
return false;
|
||||
return addTimer();
|
||||
}
|
||||
|
||||
bool sdlDispContext::handleEvent(const SDL_DisplayEvent& ev)
|
||||
{
|
||||
const auto cat = SDL_LOG_CATEGORY_APPLICATION;
|
||||
switch (ev.type)
|
||||
{
|
||||
case SDL_EVENT_DISPLAY_ADDED:
|
||||
SDL_LogDebug(cat, "A new display with id %u was connected", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
case SDL_EVENT_DISPLAY_REMOVED:
|
||||
SDL_LogDebug(cat, "The display with id %u was disconnected", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
case SDL_EVENT_DISPLAY_ORIENTATION:
|
||||
SDL_LogDebug(cat, "The orientation of display with id %u was changed", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
case SDL_EVENT_DISPLAY_MOVED:
|
||||
SDL_LogDebug(cat, "The display with id %u was moved", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED:
|
||||
SDL_LogDebug(cat, "The display with id %u changed scale", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED:
|
||||
SDL_LogDebug(cat, "The display with id %u changed mode", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED:
|
||||
SDL_LogDebug(cat, "The display with id %u changed desktop mode", ev.displayID);
|
||||
return updateMonitors(ev.type, ev.displayID);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool sdlDispContext::handleEvent(const SDL_WindowEvent& ev)
|
||||
{
|
||||
auto window = _sdl->getWindowForId(ev.windowID);
|
||||
if (!window)
|
||||
return true;
|
||||
|
||||
auto bordered = freerdp_settings_get_bool(_sdl->context()->settings, FreeRDP_Decorations);
|
||||
window->setBordered(bordered);
|
||||
|
||||
switch (ev.type)
|
||||
{
|
||||
case SDL_EVENT_WINDOW_HIDDEN:
|
||||
case SDL_EVENT_WINDOW_MINIMIZED:
|
||||
return _sdl->redraw(true);
|
||||
case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
|
||||
return updateMonitor(ev.windowID);
|
||||
case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
|
||||
return updateMonitor(ev.windowID);
|
||||
|
||||
case SDL_EVENT_WINDOW_EXPOSED:
|
||||
case SDL_EVENT_WINDOW_SHOWN:
|
||||
case SDL_EVENT_WINDOW_MAXIMIZED:
|
||||
case SDL_EVENT_WINDOW_RESTORED:
|
||||
if (!_sdl->redraw())
|
||||
return false;
|
||||
|
||||
/* fallthrough */
|
||||
WINPR_FALLTHROUGH
|
||||
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
|
||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
return updateMonitor(ev.windowID);
|
||||
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
||||
WINPR_ASSERT(_sdl);
|
||||
return _sdl->getInputChannelContext().keyboard_grab(ev.windowID, false);
|
||||
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
||||
WINPR_ASSERT(_sdl);
|
||||
if (!_sdl->getInputChannelContext().keyboard_grab(ev.windowID, true))
|
||||
return false;
|
||||
return _sdl->getInputChannelContext().keyboard_focus_in();
|
||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||
return _sdl->getInputChannelContext().keyboard_focus_in();
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
UINT sdlDispContext::DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
|
||||
UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
|
||||
{
|
||||
/* we're called only if dynamic resolution update is activated */
|
||||
WINPR_ASSERT(disp);
|
||||
|
||||
auto sdlDisp = reinterpret_cast<sdlDispContext*>(disp->custom);
|
||||
return sdlDisp->DisplayControlCaps(maxNumMonitors, maxMonitorAreaFactorA,
|
||||
maxMonitorAreaFactorB);
|
||||
}
|
||||
|
||||
UINT sdlDispContext::DisplayControlCaps(UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA,
|
||||
UINT32 maxMonitorAreaFactorB)
|
||||
{
|
||||
auto settings = _sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
WLog_DBG(TAG,
|
||||
"DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
|
||||
" MaxMonitorAreaFactorB: %" PRIu32 "",
|
||||
maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
|
||||
_activated = true;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
|
||||
return setWindowResizeable() ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
bool sdlDispContext::init(DispClientContext* disp)
|
||||
{
|
||||
if (!disp)
|
||||
return false;
|
||||
|
||||
auto settings = _sdl->context()->settings;
|
||||
|
||||
if (!settings)
|
||||
return false;
|
||||
|
||||
_disp = disp;
|
||||
disp->custom = this;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
|
||||
{
|
||||
disp->DisplayControlCaps = sdlDispContext::DisplayControlCaps;
|
||||
}
|
||||
|
||||
return _sdl->setResizeable(true);
|
||||
}
|
||||
|
||||
bool sdlDispContext::uninit(DispClientContext* disp)
|
||||
{
|
||||
if (!disp)
|
||||
return false;
|
||||
|
||||
_disp = nullptr;
|
||||
return _sdl->setResizeable(false);
|
||||
}
|
||||
|
||||
sdlDispContext::sdlDispContext(SdlContext* sdl) : _sdl(sdl)
|
||||
{
|
||||
WINPR_ASSERT(_sdl);
|
||||
WINPR_ASSERT(_sdl->context()->settings);
|
||||
WINPR_ASSERT(_sdl->context()->pubSub);
|
||||
|
||||
auto pubSub = _sdl->context()->pubSub;
|
||||
|
||||
if (PubSub_SubscribeActivated(pubSub, sdlDispContext::OnActivated) < 0)
|
||||
throw std::exception();
|
||||
if (PubSub_SubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset) < 0)
|
||||
throw std::exception();
|
||||
std::ignore = addTimer();
|
||||
}
|
||||
|
||||
sdlDispContext::~sdlDispContext()
|
||||
{
|
||||
wPubSub* pubSub = _sdl->context()->pubSub;
|
||||
WINPR_ASSERT(pubSub);
|
||||
|
||||
PubSub_UnsubscribeActivated(pubSub, sdlDispContext::OnActivated);
|
||||
PubSub_UnsubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset);
|
||||
SDL_RemoveTimer(_timer);
|
||||
}
|
||||
78
third_party/FreeRDP/client/SDL/SDL3/sdl_disp.hpp
vendored
Normal file
78
third_party/FreeRDP/client/SDL/SDL3/sdl_disp.hpp
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Display Control Channel
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/event.h>
|
||||
#include <freerdp/client/disp.h>
|
||||
|
||||
#include "sdl_types.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
class sdlDispContext
|
||||
{
|
||||
|
||||
public:
|
||||
explicit sdlDispContext(SdlContext* sdl);
|
||||
sdlDispContext(const sdlDispContext& other) = delete;
|
||||
sdlDispContext(sdlDispContext&& other) = delete;
|
||||
virtual ~sdlDispContext();
|
||||
|
||||
sdlDispContext& operator=(const sdlDispContext& other) = delete;
|
||||
sdlDispContext& operator=(sdlDispContext&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool init(DispClientContext* disp);
|
||||
[[nodiscard]] bool uninit(DispClientContext* disp);
|
||||
|
||||
[[nodiscard]] bool handleEvent(const SDL_DisplayEvent& ev);
|
||||
[[nodiscard]] bool handleEvent(const SDL_WindowEvent& ev);
|
||||
|
||||
private:
|
||||
[[nodiscard]] UINT DisplayControlCaps(UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA,
|
||||
UINT32 maxMonitorAreaFactorB);
|
||||
[[nodiscard]] bool setWindowResizeable();
|
||||
|
||||
[[nodiscard]] bool sendResize();
|
||||
[[nodiscard]] bool settings_changed(const std::vector<DISPLAY_CONTROL_MONITOR_LAYOUT>& layout);
|
||||
[[nodiscard]] bool sendLayout(const rdpMonitor* monitors, size_t nmonitors);
|
||||
|
||||
[[nodiscard]] bool addTimer();
|
||||
|
||||
[[nodiscard]] bool updateMonitor(SDL_WindowID id);
|
||||
[[nodiscard]] bool updateMonitors(SDL_EventType type, SDL_DisplayID displayID);
|
||||
|
||||
[[nodiscard]] static UINT DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
|
||||
UINT32 maxMonitorAreaFactorA,
|
||||
UINT32 maxMonitorAreaFactorB);
|
||||
static void OnActivated(void* context, const ActivatedEventArgs* e);
|
||||
static void OnGraphicsReset(void* context, const GraphicsResetEventArgs* e);
|
||||
[[nodiscard]] static Uint32 SDLCALL OnTimer(void* param, SDL_TimerID timerID, Uint32 interval);
|
||||
|
||||
SdlContext* _sdl = nullptr;
|
||||
DispClientContext* _disp = nullptr;
|
||||
UINT64 _lastSentDate = 0;
|
||||
bool _activated = false;
|
||||
bool _waitingResize = false;
|
||||
SDL_TimerID _timer = 0;
|
||||
unsigned _timer_retries = 0;
|
||||
std::vector<DISPLAY_CONTROL_MONITOR_LAYOUT> _last_sent_layout;
|
||||
};
|
||||
657
third_party/FreeRDP/client/SDL/SDL3/sdl_freerdp.cpp
vendored
Normal file
657
third_party/FreeRDP/client/SDL/SDL3/sdl_freerdp.cpp
vendored
Normal file
@@ -0,0 +1,657 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP SDL UI
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/streamdump.h>
|
||||
#include <freerdp/utils/signal.h>
|
||||
|
||||
#include <freerdp/channels/channels.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/client/file.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/config.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#if !defined(__MINGW32__)
|
||||
#include <SDL3/SDL_main.h>
|
||||
#endif
|
||||
#include <SDL3/SDL_hints.h>
|
||||
#include <SDL3/SDL_oldnames.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
#include <sdl_config.hpp>
|
||||
|
||||
#include "dialogs/sdl_connection_dialog_hider.hpp"
|
||||
#include "dialogs/sdl_dialogs.hpp"
|
||||
#include "scoped_guard.hpp"
|
||||
#include "sdl_channels.hpp"
|
||||
#include "sdl_freerdp.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
#include "sdl_monitor.hpp"
|
||||
#include "sdl_pointer.hpp"
|
||||
#include "sdl_prefs.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define SDL_TAG CLIENT_TAG("SDL")
|
||||
#endif
|
||||
|
||||
class ErrorMsg : public std::exception
|
||||
{
|
||||
public:
|
||||
ErrorMsg(int rc, Uint32 type, const std::string& msg,
|
||||
const std::string& sdlError = SDL_GetError());
|
||||
|
||||
[[nodiscard]] int rc() const;
|
||||
[[nodiscard]] const char* what() const noexcept override;
|
||||
|
||||
private:
|
||||
int _rc;
|
||||
Uint32 _type;
|
||||
std::string _msg;
|
||||
std::string _sdlError;
|
||||
std::string _buffer;
|
||||
};
|
||||
const char* ErrorMsg::what() const noexcept
|
||||
{
|
||||
return _buffer.c_str();
|
||||
}
|
||||
|
||||
int ErrorMsg::rc() const
|
||||
{
|
||||
return _rc;
|
||||
}
|
||||
|
||||
ErrorMsg::ErrorMsg(int rc, Uint32 type, const std::string& msg, const std::string& sdlError)
|
||||
: _rc(rc), _type(type), _msg(msg), _sdlError(sdlError)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << _msg << " {" << sdl::utils::toString(_type) << "}{SDL:" << sdlError << "}";
|
||||
_buffer = ss.str();
|
||||
}
|
||||
|
||||
static void sdl_term_handler([[maybe_unused]] int signum, [[maybe_unused]] const char* signame,
|
||||
[[maybe_unused]] void* context)
|
||||
{
|
||||
std::ignore = sdl_push_quit();
|
||||
}
|
||||
|
||||
[[nodiscard]] static int sdl_run(SdlContext* sdl)
|
||||
{
|
||||
int rc = -1;
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
try
|
||||
{
|
||||
while (!sdl->shallAbort())
|
||||
{
|
||||
SDL_Event windowEvent = {};
|
||||
while (!sdl->shallAbort() && SDL_WaitEventTimeout(nullptr, 1000))
|
||||
{
|
||||
/* Only poll standard SDL events and SDL_EVENT_USERS meant to create
|
||||
* dialogs. do not process the dialog return value events here.
|
||||
*/
|
||||
const int prc = SDL_PeepEvents(&windowEvent, 1, SDL_GETEVENT, SDL_EVENT_FIRST,
|
||||
SDL_EVENT_USER_RETRY_DIALOG);
|
||||
if (prc < 0)
|
||||
{
|
||||
if (sdl_log_error(prc, sdl->getWLog(), "SDL_PeepEvents"))
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_SDL_EVENTS)
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "got event %s [0x%08" PRIx32 "]",
|
||||
sdl::utils::toString(windowEvent.type).c_str(), windowEvent.type);
|
||||
#endif
|
||||
if (sdl->shallAbort(true))
|
||||
continue;
|
||||
|
||||
if (sdl->getDialog().handleEvent(windowEvent))
|
||||
continue;
|
||||
|
||||
if (!sdl->handleEvent(windowEvent))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->handleEvent" };
|
||||
|
||||
switch (windowEvent.type)
|
||||
{
|
||||
case SDL_EVENT_QUIT:
|
||||
std::ignore = freerdp_abort_connect_context(sdl->context());
|
||||
break;
|
||||
case SDL_EVENT_USER_CERT_DIALOG:
|
||||
{
|
||||
SDLConnectionDialogHider hider(sdl);
|
||||
auto title = static_cast<const char*>(windowEvent.user.data1);
|
||||
auto msg = static_cast<const char*>(windowEvent.user.data2);
|
||||
if (!sdl_cert_dialog_show(title, msg))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl_cert_dialog_show" };
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_SHOW_DIALOG:
|
||||
{
|
||||
SDLConnectionDialogHider hider(sdl);
|
||||
auto title = static_cast<const char*>(windowEvent.user.data1);
|
||||
auto msg = static_cast<const char*>(windowEvent.user.data2);
|
||||
if (!sdl_message_dialog_show(title, msg, windowEvent.user.code))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl_message_dialog_show" };
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_SCARD_DIALOG:
|
||||
{
|
||||
SDLConnectionDialogHider hider(sdl);
|
||||
auto title = static_cast<const char*>(windowEvent.user.data1);
|
||||
auto msg = static_cast<const char**>(windowEvent.user.data2);
|
||||
if (!sdl_scard_dialog_show(title, windowEvent.user.code, msg))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl_scard_dialog_show" };
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_AUTH_DIALOG:
|
||||
{
|
||||
SDLConnectionDialogHider hider(sdl);
|
||||
if (!sdl_auth_dialog_show(
|
||||
reinterpret_cast<const SDL_UserAuthArg*>(windowEvent.padding)))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl_auth_dialog_show" };
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_UPDATE:
|
||||
{
|
||||
std::vector<SDL_Rect> rectangles;
|
||||
do
|
||||
{
|
||||
rectangles = sdl->pop();
|
||||
if (!sdl->drawToWindows(rectangles))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->drawToWindows" };
|
||||
} while (!rectangles.empty());
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_CREATE_WINDOWS:
|
||||
{
|
||||
auto ctx = static_cast<SdlContext*>(windowEvent.user.data1);
|
||||
if (!ctx->createWindows())
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->createWindows" };
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_WINDOW_RESIZEABLE:
|
||||
{
|
||||
auto window = static_cast<SdlWindow*>(windowEvent.user.data1);
|
||||
const bool use = windowEvent.user.code != 0;
|
||||
if (window)
|
||||
window->resizeable(use);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_WINDOW_FULLSCREEN:
|
||||
{
|
||||
auto window = static_cast<SdlWindow*>(windowEvent.user.data1);
|
||||
const bool enter = windowEvent.user.code != 0;
|
||||
const bool forceOriginalDisplay = windowEvent.user.data2 != nullptr;
|
||||
if (window)
|
||||
window->fullscreen(enter, forceOriginalDisplay);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_WINDOW_MINIMIZE:
|
||||
if (!sdl->minimizeAllWindows())
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->minimizeAllWindows" };
|
||||
break;
|
||||
case SDL_EVENT_USER_POINTER_NULL:
|
||||
if (!sdl->setCursor(SdlContext::CURSOR_NULL))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" };
|
||||
break;
|
||||
case SDL_EVENT_USER_POINTER_DEFAULT:
|
||||
if (!sdl->setCursor(SdlContext::CURSOR_DEFAULT))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" };
|
||||
break;
|
||||
case SDL_EVENT_USER_POINTER_POSITION:
|
||||
{
|
||||
const auto x =
|
||||
static_cast<INT32>(reinterpret_cast<uintptr_t>(windowEvent.user.data1));
|
||||
const auto y =
|
||||
static_cast<INT32>(reinterpret_cast<uintptr_t>(windowEvent.user.data2));
|
||||
if (!sdl->moveMouseTo(
|
||||
{ static_cast<float>(x) * 1.0f, static_cast<float>(y) * 1.0f }))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->moveMouseTo" };
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_POINTER_SET:
|
||||
if (!sdl->setCursor(static_cast<rdpPointer*>(windowEvent.user.data1)))
|
||||
throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" };
|
||||
break;
|
||||
case SDL_EVENT_USER_QUIT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = 1;
|
||||
}
|
||||
catch (ErrorMsg& msg)
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "[exception] %s", msg.what());
|
||||
rc = msg.rc();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Optional global initializer.
|
||||
* Here we just register a signal handler to print out stack traces
|
||||
* if available. */
|
||||
[[nodiscard]] static BOOL sdl_client_global_init()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
WSADATA wsaData = {};
|
||||
const DWORD wVersionRequested = MAKEWORD(1, 1);
|
||||
const int rc = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (rc != 0)
|
||||
{
|
||||
WLog_ERR(SDL_TAG, "WSAStartup failed with %s [%d]", gai_strerrorA(rc), rc);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (freerdp_handle_signals() == 0);
|
||||
}
|
||||
|
||||
/* Optional global tear down */
|
||||
static void sdl_client_global_uninit()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_client_new(freerdp* instance, rdpContext* context)
|
||||
{
|
||||
auto sdl = reinterpret_cast<sdl_rdp_context*>(context);
|
||||
|
||||
if (!instance || !context)
|
||||
return FALSE;
|
||||
|
||||
sdl->sdl = new SdlContext(context);
|
||||
return sdl->sdl != nullptr;
|
||||
}
|
||||
|
||||
static void sdl_client_free([[maybe_unused]] freerdp* instance, rdpContext* context)
|
||||
{
|
||||
auto sdl = reinterpret_cast<sdl_rdp_context*>(context);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
delete sdl->sdl;
|
||||
}
|
||||
|
||||
[[nodiscard]] static int sdl_client_start(rdpContext* context)
|
||||
{
|
||||
auto sdl = get_context(context);
|
||||
WINPR_ASSERT(sdl);
|
||||
return sdl->start();
|
||||
}
|
||||
|
||||
[[nodiscard]] static int sdl_client_stop(rdpContext* context)
|
||||
{
|
||||
auto sdl = get_context(context);
|
||||
WINPR_ASSERT(sdl);
|
||||
return sdl->join();
|
||||
}
|
||||
|
||||
static void RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
WINPR_ASSERT(pEntryPoints);
|
||||
|
||||
ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
|
||||
pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
|
||||
pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
|
||||
pEntryPoints->GlobalInit = sdl_client_global_init;
|
||||
pEntryPoints->GlobalUninit = sdl_client_global_uninit;
|
||||
pEntryPoints->ContextSize = sizeof(sdl_rdp_context);
|
||||
pEntryPoints->ClientNew = sdl_client_new;
|
||||
pEntryPoints->ClientFree = sdl_client_free;
|
||||
pEntryPoints->ClientStart = sdl_client_start;
|
||||
pEntryPoints->ClientStop = sdl_client_stop;
|
||||
}
|
||||
|
||||
static void context_free(sdl_rdp_context* sdl)
|
||||
{
|
||||
if (sdl)
|
||||
freerdp_client_context_free(&sdl->common.context);
|
||||
}
|
||||
|
||||
[[nodiscard]] static const char* category2str(int category)
|
||||
{
|
||||
switch (category)
|
||||
{
|
||||
case SDL_LOG_CATEGORY_APPLICATION:
|
||||
return "SDL_LOG_CATEGORY_APPLICATION";
|
||||
case SDL_LOG_CATEGORY_ERROR:
|
||||
return "SDL_LOG_CATEGORY_ERROR";
|
||||
case SDL_LOG_CATEGORY_ASSERT:
|
||||
return "SDL_LOG_CATEGORY_ASSERT";
|
||||
case SDL_LOG_CATEGORY_SYSTEM:
|
||||
return "SDL_LOG_CATEGORY_SYSTEM";
|
||||
case SDL_LOG_CATEGORY_AUDIO:
|
||||
return "SDL_LOG_CATEGORY_AUDIO";
|
||||
case SDL_LOG_CATEGORY_VIDEO:
|
||||
return "SDL_LOG_CATEGORY_VIDEO";
|
||||
case SDL_LOG_CATEGORY_RENDER:
|
||||
return "SDL_LOG_CATEGORY_RENDER";
|
||||
case SDL_LOG_CATEGORY_INPUT:
|
||||
return "SDL_LOG_CATEGORY_INPUT";
|
||||
case SDL_LOG_CATEGORY_TEST:
|
||||
return "SDL_LOG_CATEGORY_TEST";
|
||||
case SDL_LOG_CATEGORY_GPU:
|
||||
return "SDL_LOG_CATEGORY_GPU";
|
||||
case SDL_LOG_CATEGORY_RESERVED2:
|
||||
return "SDL_LOG_CATEGORY_RESERVED2";
|
||||
case SDL_LOG_CATEGORY_RESERVED3:
|
||||
return "SDL_LOG_CATEGORY_RESERVED3";
|
||||
case SDL_LOG_CATEGORY_RESERVED4:
|
||||
return "SDL_LOG_CATEGORY_RESERVED4";
|
||||
case SDL_LOG_CATEGORY_RESERVED5:
|
||||
return "SDL_LOG_CATEGORY_RESERVED5";
|
||||
case SDL_LOG_CATEGORY_RESERVED6:
|
||||
return "SDL_LOG_CATEGORY_RESERVED6";
|
||||
case SDL_LOG_CATEGORY_RESERVED7:
|
||||
return "SDL_LOG_CATEGORY_RESERVED7";
|
||||
case SDL_LOG_CATEGORY_RESERVED8:
|
||||
return "SDL_LOG_CATEGORY_RESERVED8";
|
||||
case SDL_LOG_CATEGORY_RESERVED9:
|
||||
return "SDL_LOG_CATEGORY_RESERVED9";
|
||||
case SDL_LOG_CATEGORY_RESERVED10:
|
||||
return "SDL_LOG_CATEGORY_RESERVED10";
|
||||
case SDL_LOG_CATEGORY_CUSTOM:
|
||||
default:
|
||||
return "SDL_LOG_CATEGORY_CUSTOM";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static SDL_LogPriority wloglevel2dl(DWORD level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case WLOG_TRACE:
|
||||
return SDL_LOG_PRIORITY_VERBOSE;
|
||||
case WLOG_DEBUG:
|
||||
return SDL_LOG_PRIORITY_DEBUG;
|
||||
case WLOG_INFO:
|
||||
return SDL_LOG_PRIORITY_INFO;
|
||||
case WLOG_WARN:
|
||||
return SDL_LOG_PRIORITY_WARN;
|
||||
case WLOG_ERROR:
|
||||
return SDL_LOG_PRIORITY_ERROR;
|
||||
case WLOG_FATAL:
|
||||
return SDL_LOG_PRIORITY_CRITICAL;
|
||||
case WLOG_OFF:
|
||||
default:
|
||||
return SDL_LOG_PRIORITY_VERBOSE;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static DWORD sdlpriority2wlog(SDL_LogPriority priority)
|
||||
{
|
||||
DWORD level = WLOG_OFF;
|
||||
switch (priority)
|
||||
{
|
||||
case SDL_LOG_PRIORITY_VERBOSE:
|
||||
level = WLOG_TRACE;
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_DEBUG:
|
||||
level = WLOG_DEBUG;
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_INFO:
|
||||
level = WLOG_INFO;
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_WARN:
|
||||
level = WLOG_WARN;
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_ERROR:
|
||||
level = WLOG_ERROR;
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_CRITICAL:
|
||||
level = WLOG_FATAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static void SDLCALL winpr_LogOutputFunction(void* userdata, int category, SDL_LogPriority priority,
|
||||
const char* message)
|
||||
{
|
||||
auto sdl = static_cast<SdlContext*>(userdata);
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
const DWORD level = sdlpriority2wlog(priority);
|
||||
auto log = sdl->getWLog();
|
||||
if (!WLog_IsLevelActive(log, level))
|
||||
return;
|
||||
|
||||
WLog_PrintTextMessage(log, level, __LINE__, __FILE__, __func__, "[%s] %s",
|
||||
category2str(category), message);
|
||||
}
|
||||
|
||||
static void sdl_quit()
|
||||
{
|
||||
const auto cat = SDL_LOG_CATEGORY_APPLICATION;
|
||||
SDL_Event ev = {};
|
||||
ev.type = SDL_EVENT_QUIT;
|
||||
if (!SDL_PushEvent(&ev))
|
||||
{
|
||||
SDL_LogError(cat, "An error occurred: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
static void SDLCALL rdp_file_cb(void* userdata, const char* const* filelist,
|
||||
WINPR_ATTR_UNUSED int filter)
|
||||
{
|
||||
auto rdp = static_cast<std::string*>(userdata);
|
||||
|
||||
const auto cat = SDL_LOG_CATEGORY_APPLICATION;
|
||||
if (!filelist)
|
||||
{
|
||||
SDL_LogError(cat, "An error occurred: %s", SDL_GetError());
|
||||
sdl_quit();
|
||||
return;
|
||||
}
|
||||
else if (!*filelist)
|
||||
{
|
||||
SDL_LogError(cat, "The user did not select any file.");
|
||||
SDL_LogError(cat, "Most likely, the dialog was canceled.");
|
||||
sdl_quit();
|
||||
return;
|
||||
}
|
||||
|
||||
while (*filelist)
|
||||
{
|
||||
SDL_LogError(cat, "Full path to selected file: '%s'", *filelist);
|
||||
*rdp = *filelist;
|
||||
filelist++;
|
||||
}
|
||||
|
||||
sdl_quit();
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::string getRdpFile()
|
||||
{
|
||||
const auto flags = SDL_INIT_VIDEO | SDL_INIT_EVENTS;
|
||||
SDL_DialogFileFilter filters[] = { { "RDP files", "rdp;rdpw" } };
|
||||
std::string rdp;
|
||||
|
||||
bool running = true;
|
||||
if (!SDL_Init(flags))
|
||||
return {};
|
||||
|
||||
auto props = SDL_CreateProperties();
|
||||
SDL_SetStringProperty(props, SDL_PROP_FILE_DIALOG_TITLE_STRING,
|
||||
"SDL Freerdp - Open a RDP file");
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false);
|
||||
SDL_SetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, filters);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, ARRAYSIZE(filters));
|
||||
SDL_ShowFileDialogWithProperties(SDL_FILEDIALOG_OPENFILE, rdp_file_cb, &rdp, props);
|
||||
SDL_DestroyProperties(props);
|
||||
|
||||
do
|
||||
{
|
||||
SDL_Event event = {};
|
||||
std::ignore = SDL_PollEvent(&event);
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_QUIT:
|
||||
running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (running);
|
||||
SDL_Quit();
|
||||
return rdp;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
RDP_CLIENT_ENTRY_POINTS clientEntryPoints = {};
|
||||
|
||||
/* Allocate the RDP context first, we need to pass it to SDL */
|
||||
RdpClientEntry(&clientEntryPoints);
|
||||
std::unique_ptr<sdl_rdp_context, void (*)(sdl_rdp_context*)> sdl_rdp(
|
||||
reinterpret_cast<sdl_rdp_context*>(freerdp_client_context_new(&clientEntryPoints)),
|
||||
context_free);
|
||||
|
||||
if (!sdl_rdp)
|
||||
return -1;
|
||||
auto sdl = sdl_rdp->sdl;
|
||||
|
||||
auto settings = sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
std::string rdp_file;
|
||||
std::vector<char*> args;
|
||||
args.reserve(WINPR_ASSERTING_INT_CAST(size_t, argc));
|
||||
for (auto x = 0; x < argc; x++)
|
||||
args.push_back(argv[x]);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
rdp_file = getRdpFile();
|
||||
if (!rdp_file.empty())
|
||||
{
|
||||
args.push_back(rdp_file.data());
|
||||
}
|
||||
}
|
||||
|
||||
auto status = freerdp_client_settings_parse_command_line(
|
||||
settings, WINPR_ASSERTING_INT_CAST(int, args.size()), args.data(), FALSE);
|
||||
sdl_rdp->sdl->setMetadata();
|
||||
if (status)
|
||||
{
|
||||
rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_ListMonitors))
|
||||
{
|
||||
if (!sdl_list_monitors(sdl))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case COMMAND_LINE_STATUS_PRINT:
|
||||
case COMMAND_LINE_STATUS_PRINT_VERSION:
|
||||
case COMMAND_LINE_STATUS_PRINT_BUILDCONFIG:
|
||||
break;
|
||||
case COMMAND_LINE_STATUS_PRINT_HELP:
|
||||
default:
|
||||
SdlPref::print_config_file_help(3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Basic SDL initialization */
|
||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||
return -1;
|
||||
|
||||
SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, "0");
|
||||
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
|
||||
SDL_SetHint(SDL_HINT_PEN_MOUSE_EVENTS, "0");
|
||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||
SDL_SetHint(SDL_HINT_PEN_TOUCH_EVENTS, "1");
|
||||
SDL_SetHint(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, "1");
|
||||
|
||||
/* Redirect SDL log messages to wLog */
|
||||
SDL_SetLogOutputFunction(winpr_LogOutputFunction, sdl);
|
||||
auto level = WLog_GetLogLevel(sdl->getWLog());
|
||||
SDL_SetLogPriorities(wloglevel2dl(level));
|
||||
|
||||
auto backend = SDL_GetCurrentVideoDriver();
|
||||
WLog_Print(sdl->getWLog(), WLOG_DEBUG, "client is using backend '%s'", backend);
|
||||
sdl_dialogs_init();
|
||||
|
||||
/* SDL cleanup code if the client exits */
|
||||
ScopeGuard guard(
|
||||
[&]()
|
||||
{
|
||||
sdl->cleanup();
|
||||
freerdp_del_signal_cleanup_handler(sdl->context(), sdl_term_handler);
|
||||
sdl_dialogs_uninit();
|
||||
SDL_Quit();
|
||||
});
|
||||
if (!sdl->detectDisplays())
|
||||
return -1;
|
||||
|
||||
/* Initialize RDP */
|
||||
auto context = sdl->context();
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!stream_dump_register_handlers(context, CONNECTION_STATE_MCS_CREATE_REQUEST, FALSE))
|
||||
return -1;
|
||||
|
||||
if (freerdp_client_start(context) != 0)
|
||||
return -1;
|
||||
|
||||
rc = sdl_run(sdl);
|
||||
|
||||
if (freerdp_client_stop(context) != 0)
|
||||
return -1;
|
||||
|
||||
if (sdl->exitCode() != 0)
|
||||
rc = sdl->exitCode();
|
||||
|
||||
return rc;
|
||||
}
|
||||
22
third_party/FreeRDP/client/SDL/SDL3/sdl_freerdp.hpp
vendored
Normal file
22
third_party/FreeRDP/client/SDL/SDL3/sdl_freerdp.hpp
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdl_context.hpp"
|
||||
717
third_party/FreeRDP/client/SDL/SDL3/sdl_input.cpp
vendored
Normal file
717
third_party/FreeRDP/client/SDL/SDL3/sdl_input.cpp
vendored
Normal file
@@ -0,0 +1,717 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP SDL keyboard helper
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "sdl_input.hpp"
|
||||
#include "sdl_disp.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
#include "sdl_prefs.hpp"
|
||||
#include "sdl_touch.hpp"
|
||||
|
||||
#include <SDL3/SDL_oldnames.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <freerdp/utils/string.h>
|
||||
#include <freerdp/scancode.h>
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
#include <freerdp/locale/locale.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint32 sdl;
|
||||
const char* sdl_name;
|
||||
UINT32 rdp;
|
||||
const char* rdp_name;
|
||||
} scancode_entry_t;
|
||||
|
||||
#define STR(x) #x
|
||||
#define ENTRY(x, y) { x, STR(x), y, #y }
|
||||
static const scancode_entry_t map[] = {
|
||||
ENTRY(SDL_SCANCODE_UNKNOWN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_A, RDP_SCANCODE_KEY_A),
|
||||
ENTRY(SDL_SCANCODE_B, RDP_SCANCODE_KEY_B),
|
||||
ENTRY(SDL_SCANCODE_C, RDP_SCANCODE_KEY_C),
|
||||
ENTRY(SDL_SCANCODE_D, RDP_SCANCODE_KEY_D),
|
||||
ENTRY(SDL_SCANCODE_E, RDP_SCANCODE_KEY_E),
|
||||
ENTRY(SDL_SCANCODE_F, RDP_SCANCODE_KEY_F),
|
||||
ENTRY(SDL_SCANCODE_G, RDP_SCANCODE_KEY_G),
|
||||
ENTRY(SDL_SCANCODE_H, RDP_SCANCODE_KEY_H),
|
||||
ENTRY(SDL_SCANCODE_I, RDP_SCANCODE_KEY_I),
|
||||
ENTRY(SDL_SCANCODE_J, RDP_SCANCODE_KEY_J),
|
||||
ENTRY(SDL_SCANCODE_K, RDP_SCANCODE_KEY_K),
|
||||
ENTRY(SDL_SCANCODE_L, RDP_SCANCODE_KEY_L),
|
||||
ENTRY(SDL_SCANCODE_M, RDP_SCANCODE_KEY_M),
|
||||
ENTRY(SDL_SCANCODE_N, RDP_SCANCODE_KEY_N),
|
||||
ENTRY(SDL_SCANCODE_O, RDP_SCANCODE_KEY_O),
|
||||
ENTRY(SDL_SCANCODE_P, RDP_SCANCODE_KEY_P),
|
||||
ENTRY(SDL_SCANCODE_Q, RDP_SCANCODE_KEY_Q),
|
||||
ENTRY(SDL_SCANCODE_R, RDP_SCANCODE_KEY_R),
|
||||
ENTRY(SDL_SCANCODE_S, RDP_SCANCODE_KEY_S),
|
||||
ENTRY(SDL_SCANCODE_T, RDP_SCANCODE_KEY_T),
|
||||
ENTRY(SDL_SCANCODE_U, RDP_SCANCODE_KEY_U),
|
||||
ENTRY(SDL_SCANCODE_V, RDP_SCANCODE_KEY_V),
|
||||
ENTRY(SDL_SCANCODE_W, RDP_SCANCODE_KEY_W),
|
||||
ENTRY(SDL_SCANCODE_X, RDP_SCANCODE_KEY_X),
|
||||
ENTRY(SDL_SCANCODE_Y, RDP_SCANCODE_KEY_Y),
|
||||
ENTRY(SDL_SCANCODE_Z, RDP_SCANCODE_KEY_Z),
|
||||
ENTRY(SDL_SCANCODE_1, RDP_SCANCODE_KEY_1),
|
||||
ENTRY(SDL_SCANCODE_2, RDP_SCANCODE_KEY_2),
|
||||
ENTRY(SDL_SCANCODE_3, RDP_SCANCODE_KEY_3),
|
||||
ENTRY(SDL_SCANCODE_4, RDP_SCANCODE_KEY_4),
|
||||
ENTRY(SDL_SCANCODE_5, RDP_SCANCODE_KEY_5),
|
||||
ENTRY(SDL_SCANCODE_6, RDP_SCANCODE_KEY_6),
|
||||
ENTRY(SDL_SCANCODE_7, RDP_SCANCODE_KEY_7),
|
||||
ENTRY(SDL_SCANCODE_8, RDP_SCANCODE_KEY_8),
|
||||
ENTRY(SDL_SCANCODE_9, RDP_SCANCODE_KEY_9),
|
||||
ENTRY(SDL_SCANCODE_0, RDP_SCANCODE_KEY_0),
|
||||
ENTRY(SDL_SCANCODE_RETURN, RDP_SCANCODE_RETURN),
|
||||
ENTRY(SDL_SCANCODE_ESCAPE, RDP_SCANCODE_ESCAPE),
|
||||
ENTRY(SDL_SCANCODE_BACKSPACE, RDP_SCANCODE_BACKSPACE),
|
||||
ENTRY(SDL_SCANCODE_TAB, RDP_SCANCODE_TAB),
|
||||
ENTRY(SDL_SCANCODE_SPACE, RDP_SCANCODE_SPACE),
|
||||
ENTRY(SDL_SCANCODE_MINUS, RDP_SCANCODE_OEM_MINUS),
|
||||
ENTRY(SDL_SCANCODE_CAPSLOCK, RDP_SCANCODE_CAPSLOCK),
|
||||
ENTRY(SDL_SCANCODE_F1, RDP_SCANCODE_F1),
|
||||
ENTRY(SDL_SCANCODE_F2, RDP_SCANCODE_F2),
|
||||
ENTRY(SDL_SCANCODE_F3, RDP_SCANCODE_F3),
|
||||
ENTRY(SDL_SCANCODE_F4, RDP_SCANCODE_F4),
|
||||
ENTRY(SDL_SCANCODE_F5, RDP_SCANCODE_F5),
|
||||
ENTRY(SDL_SCANCODE_F6, RDP_SCANCODE_F6),
|
||||
ENTRY(SDL_SCANCODE_F7, RDP_SCANCODE_F7),
|
||||
ENTRY(SDL_SCANCODE_F8, RDP_SCANCODE_F8),
|
||||
ENTRY(SDL_SCANCODE_F9, RDP_SCANCODE_F9),
|
||||
ENTRY(SDL_SCANCODE_F10, RDP_SCANCODE_F10),
|
||||
ENTRY(SDL_SCANCODE_F11, RDP_SCANCODE_F11),
|
||||
ENTRY(SDL_SCANCODE_F12, RDP_SCANCODE_F12),
|
||||
ENTRY(SDL_SCANCODE_F13, RDP_SCANCODE_F13),
|
||||
ENTRY(SDL_SCANCODE_F14, RDP_SCANCODE_F14),
|
||||
ENTRY(SDL_SCANCODE_F15, RDP_SCANCODE_F15),
|
||||
ENTRY(SDL_SCANCODE_F16, RDP_SCANCODE_F16),
|
||||
ENTRY(SDL_SCANCODE_F17, RDP_SCANCODE_F17),
|
||||
ENTRY(SDL_SCANCODE_F18, RDP_SCANCODE_F18),
|
||||
ENTRY(SDL_SCANCODE_F19, RDP_SCANCODE_F19),
|
||||
ENTRY(SDL_SCANCODE_F20, RDP_SCANCODE_F20),
|
||||
ENTRY(SDL_SCANCODE_F21, RDP_SCANCODE_F21),
|
||||
ENTRY(SDL_SCANCODE_F22, RDP_SCANCODE_F22),
|
||||
ENTRY(SDL_SCANCODE_F23, RDP_SCANCODE_F23),
|
||||
ENTRY(SDL_SCANCODE_F24, RDP_SCANCODE_F24),
|
||||
ENTRY(SDL_SCANCODE_NUMLOCKCLEAR, RDP_SCANCODE_NUMLOCK),
|
||||
ENTRY(SDL_SCANCODE_KP_DIVIDE, RDP_SCANCODE_DIVIDE),
|
||||
ENTRY(SDL_SCANCODE_KP_MULTIPLY, RDP_SCANCODE_MULTIPLY),
|
||||
ENTRY(SDL_SCANCODE_KP_MINUS, RDP_SCANCODE_SUBTRACT),
|
||||
ENTRY(SDL_SCANCODE_KP_PLUS, RDP_SCANCODE_ADD),
|
||||
ENTRY(SDL_SCANCODE_KP_ENTER, RDP_SCANCODE_RETURN_KP),
|
||||
ENTRY(SDL_SCANCODE_KP_1, RDP_SCANCODE_NUMPAD1),
|
||||
ENTRY(SDL_SCANCODE_KP_2, RDP_SCANCODE_NUMPAD2),
|
||||
ENTRY(SDL_SCANCODE_KP_3, RDP_SCANCODE_NUMPAD3),
|
||||
ENTRY(SDL_SCANCODE_KP_4, RDP_SCANCODE_NUMPAD4),
|
||||
ENTRY(SDL_SCANCODE_KP_5, RDP_SCANCODE_NUMPAD5),
|
||||
ENTRY(SDL_SCANCODE_KP_6, RDP_SCANCODE_NUMPAD6),
|
||||
ENTRY(SDL_SCANCODE_KP_7, RDP_SCANCODE_NUMPAD7),
|
||||
ENTRY(SDL_SCANCODE_KP_8, RDP_SCANCODE_NUMPAD8),
|
||||
ENTRY(SDL_SCANCODE_KP_9, RDP_SCANCODE_NUMPAD9),
|
||||
ENTRY(SDL_SCANCODE_KP_0, RDP_SCANCODE_NUMPAD0),
|
||||
ENTRY(SDL_SCANCODE_KP_PERIOD, RDP_SCANCODE_DECIMAL),
|
||||
ENTRY(SDL_SCANCODE_LCTRL, RDP_SCANCODE_LCONTROL),
|
||||
ENTRY(SDL_SCANCODE_LSHIFT, RDP_SCANCODE_LSHIFT),
|
||||
ENTRY(SDL_SCANCODE_LALT, RDP_SCANCODE_LMENU),
|
||||
ENTRY(SDL_SCANCODE_LGUI, RDP_SCANCODE_LWIN),
|
||||
ENTRY(SDL_SCANCODE_RCTRL, RDP_SCANCODE_RCONTROL),
|
||||
ENTRY(SDL_SCANCODE_RSHIFT, RDP_SCANCODE_RSHIFT),
|
||||
ENTRY(SDL_SCANCODE_RALT, RDP_SCANCODE_RMENU),
|
||||
ENTRY(SDL_SCANCODE_RGUI, RDP_SCANCODE_RWIN),
|
||||
ENTRY(SDL_SCANCODE_MODE, RDP_SCANCODE_APPS),
|
||||
ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
|
||||
ENTRY(SDL_SCANCODE_VOLUMEUP, RDP_SCANCODE_VOLUME_UP),
|
||||
ENTRY(SDL_SCANCODE_VOLUMEDOWN, RDP_SCANCODE_VOLUME_DOWN),
|
||||
ENTRY(SDL_SCANCODE_GRAVE, RDP_SCANCODE_OEM_3),
|
||||
ENTRY(SDL_SCANCODE_COMMA, RDP_SCANCODE_OEM_COMMA),
|
||||
ENTRY(SDL_SCANCODE_PERIOD, RDP_SCANCODE_OEM_PERIOD),
|
||||
ENTRY(SDL_SCANCODE_SLASH, RDP_SCANCODE_OEM_2),
|
||||
ENTRY(SDL_SCANCODE_BACKSLASH, RDP_SCANCODE_OEM_5),
|
||||
ENTRY(SDL_SCANCODE_SCROLLLOCK, RDP_SCANCODE_SCROLLLOCK),
|
||||
ENTRY(SDL_SCANCODE_INSERT, RDP_SCANCODE_INSERT),
|
||||
ENTRY(SDL_SCANCODE_PRINTSCREEN, RDP_SCANCODE_PRINTSCREEN),
|
||||
ENTRY(SDL_SCANCODE_HOME, RDP_SCANCODE_HOME),
|
||||
ENTRY(SDL_SCANCODE_DELETE, RDP_SCANCODE_DELETE),
|
||||
ENTRY(SDL_SCANCODE_RIGHT, RDP_SCANCODE_RIGHT),
|
||||
ENTRY(SDL_SCANCODE_LEFT, RDP_SCANCODE_LEFT),
|
||||
ENTRY(SDL_SCANCODE_DOWN, RDP_SCANCODE_DOWN),
|
||||
ENTRY(SDL_SCANCODE_UP, RDP_SCANCODE_UP),
|
||||
ENTRY(SDL_SCANCODE_SEMICOLON, RDP_SCANCODE_OEM_1),
|
||||
ENTRY(SDL_SCANCODE_PAUSE, RDP_SCANCODE_PAUSE),
|
||||
ENTRY(SDL_SCANCODE_PAGEUP, RDP_SCANCODE_PRIOR),
|
||||
ENTRY(SDL_SCANCODE_END, RDP_SCANCODE_END),
|
||||
ENTRY(SDL_SCANCODE_PAGEDOWN, RDP_SCANCODE_NEXT),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_NEXT_TRACK, RDP_SCANCODE_MEDIA_NEXT_TRACK),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, RDP_SCANCODE_MEDIA_PREV_TRACK),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_STOP, RDP_SCANCODE_MEDIA_STOP),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_PLAY, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
|
||||
ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_SELECT, RDP_SCANCODE_LAUNCH_MEDIA_SELECT),
|
||||
ENTRY(SDL_SCANCODE_SYSREQ, RDP_SCANCODE_SYSREQ),
|
||||
ENTRY(SDL_SCANCODE_LEFTBRACKET, RDP_SCANCODE_OEM_4),
|
||||
ENTRY(SDL_SCANCODE_RIGHTBRACKET, RDP_SCANCODE_OEM_6),
|
||||
ENTRY(SDL_SCANCODE_APOSTROPHE, RDP_SCANCODE_OEM_7),
|
||||
ENTRY(SDL_SCANCODE_NONUSBACKSLASH, RDP_SCANCODE_OEM_102),
|
||||
ENTRY(SDL_SCANCODE_SLEEP, RDP_SCANCODE_SLEEP),
|
||||
ENTRY(SDL_SCANCODE_EQUALS, RDP_SCANCODE_OEM_PLUS),
|
||||
ENTRY(SDL_SCANCODE_KP_COMMA, RDP_SCANCODE_DECIMAL),
|
||||
ENTRY(SDL_SCANCODE_FIND, RDP_SCANCODE_BROWSER_SEARCH),
|
||||
ENTRY(SDL_SCANCODE_RETURN2, RDP_SCANCODE_RETURN_KP),
|
||||
ENTRY(SDL_SCANCODE_AC_SEARCH, RDP_SCANCODE_BROWSER_SEARCH),
|
||||
ENTRY(SDL_SCANCODE_AC_HOME, RDP_SCANCODE_BROWSER_HOME),
|
||||
ENTRY(SDL_SCANCODE_AC_BACK, RDP_SCANCODE_BROWSER_BACK),
|
||||
ENTRY(SDL_SCANCODE_AC_FORWARD, RDP_SCANCODE_BROWSER_FORWARD),
|
||||
ENTRY(SDL_SCANCODE_AC_STOP, RDP_SCANCODE_BROWSER_STOP),
|
||||
|
||||
ENTRY(SDL_SCANCODE_NONUSHASH, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_APPLICATION, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_POWER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_EQUALS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_EXECUTE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_HELP, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MENU, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_SELECT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_STOP, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_AGAIN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_UNDO, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CUT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_COPY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_PASTE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_EQUALSAS400, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL1, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL2, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL3, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL4, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL5, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL6, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL7, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL8, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL9, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG1, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG2, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG3, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG4, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG5, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG6, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG7, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG8, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG9, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_ALTERASE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CANCEL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CLEAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_PRIOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_SEPARATOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_OUT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_OPER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CLEARAGAIN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CRSEL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_EXSEL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_00, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_000, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_THOUSANDSSEPARATOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_DECIMALSEPARATOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CURRENCYUNIT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CURRENCYSUBUNIT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_LEFTPAREN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_RIGHTPAREN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_LEFTBRACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_RIGHTBRACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_TAB, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_BACKSPACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_A, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_B, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_C, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_D, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_E, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_F, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_XOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_POWER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_PERCENT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_LESS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_GREATER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_AMPERSAND, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_DBLAMPERSAND, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_VERTICALBAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_DBLVERTICALBAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_COLON, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_HASH, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_SPACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_AT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_EXCLAM, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMSTORE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMRECALL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMCLEAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMADD, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMSUBTRACT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMMULTIPLY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMDIVIDE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_PLUSMINUS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_CLEAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_CLEARENTRY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_BINARY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_OCTAL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_DECIMAL, RDP_SCANCODE_DECIMAL),
|
||||
ENTRY(SDL_SCANCODE_KP_HEXADECIMAL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_AC_REFRESH, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_AC_BOOKMARKS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_EJECT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_REWIND, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_FAST_FORWARD, RDP_SCANCODE_UNKNOWN)
|
||||
};
|
||||
|
||||
[[nodiscard]] static UINT32 sdl_get_kbd_flags()
|
||||
{
|
||||
UINT32 flags = 0;
|
||||
|
||||
SDL_Keymod mod = SDL_GetModState();
|
||||
if ((mod & SDL_KMOD_NUM) != 0)
|
||||
flags |= KBD_SYNC_NUM_LOCK;
|
||||
if ((mod & SDL_KMOD_CAPS) != 0)
|
||||
flags |= KBD_SYNC_CAPS_LOCK;
|
||||
if ((mod & SDL_KMOD_SCROLL) != 0)
|
||||
flags |= KBD_SYNC_SCROLL_LOCK;
|
||||
|
||||
// TODO: KBD_SYNC_KANA_LOCK
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool sdlInput::keyboard_sync_state()
|
||||
{
|
||||
const UINT32 syncFlags = sdl_get_kbd_flags();
|
||||
return freerdp_input_send_synchronize_event(_sdl->context()->input, syncFlags);
|
||||
}
|
||||
|
||||
bool sdlInput::keyboard_focus_in()
|
||||
{
|
||||
auto input = _sdl->context()->input;
|
||||
WINPR_ASSERT(input);
|
||||
|
||||
auto syncFlags = sdl_get_kbd_flags();
|
||||
if (!freerdp_input_send_focus_in_event(input, WINPR_ASSERTING_INT_CAST(uint16_t, syncFlags)))
|
||||
return false;
|
||||
|
||||
/* finish with a mouse pointer position like mstsc.exe if required */
|
||||
// TODO: fullscreen/remote app
|
||||
float fx = 0.0f;
|
||||
float fy = 0.0f;
|
||||
SDL_GetMouseState(&fx, &fy);
|
||||
|
||||
auto w = SDL_GetMouseFocus();
|
||||
const auto& pos = _sdl->screenToPixel(SDL_GetWindowID(w), SDL_FPoint{ fx, fy });
|
||||
|
||||
return freerdp_client_send_button_event(_sdl->common(), FALSE, PTR_FLAGS_MOVE,
|
||||
static_cast<Sint32>(pos.x), static_cast<Sint32>(pos.y));
|
||||
}
|
||||
|
||||
/* This function is called to update the keyboard indicator LED */
|
||||
BOOL sdlInput::keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
|
||||
SDL_Keymod state = SDL_KMOD_NONE;
|
||||
|
||||
if ((led_flags & KBD_SYNC_NUM_LOCK) != 0)
|
||||
state |= SDL_KMOD_NUM;
|
||||
if ((led_flags & KBD_SYNC_CAPS_LOCK) != 0)
|
||||
state |= SDL_KMOD_CAPS;
|
||||
if ((led_flags & KBD_SYNC_SCROLL_LOCK) != 0)
|
||||
state |= SDL_KMOD_SCROLL;
|
||||
if ((led_flags & KBD_SYNC_KANA_LOCK) != 0)
|
||||
state |= SDL_KMOD_LEVEL5;
|
||||
|
||||
SDL_SetModState(state);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called to set the IME state */
|
||||
BOOL sdlInput::keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
|
||||
UINT32 imeConvMode)
|
||||
{
|
||||
auto sdl = reinterpret_cast<SdlContext*>(context);
|
||||
if (!context)
|
||||
return FALSE;
|
||||
|
||||
WLog_Print(sdl->getWLog(), WLOG_WARN,
|
||||
"KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
|
||||
", imeConvMode=%08" PRIx32 ") ignored",
|
||||
imeId, imeState, imeConvMode);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const std::map<std::string, uint32_t>& getSdlMap()
|
||||
{
|
||||
static std::map<std::string, uint32_t> s_map = {
|
||||
{ "KMOD_LSHIFT", SDL_KMOD_LSHIFT }, { "KMOD_RSHIFT", SDL_KMOD_RSHIFT },
|
||||
{ "KMOD_LCTRL", SDL_KMOD_LCTRL }, { "KMOD_RCTRL", SDL_KMOD_RCTRL },
|
||||
{ "KMOD_LALT", SDL_KMOD_LALT }, { "KMOD_RALT", SDL_KMOD_RALT },
|
||||
{ "KMOD_LGUI", SDL_KMOD_LGUI }, { "KMOD_RGUI", SDL_KMOD_RGUI },
|
||||
{ "KMOD_NUM", SDL_KMOD_NUM }, { "KMOD_CAPS", SDL_KMOD_CAPS },
|
||||
{ "KMOD_MODE", SDL_KMOD_MODE }, { "KMOD_SCROLL", SDL_KMOD_SCROLL },
|
||||
{ "KMOD_CTRL", SDL_KMOD_CTRL }, { "KMOD_SHIFT", SDL_KMOD_SHIFT },
|
||||
{ "KMOD_ALT", SDL_KMOD_ALT }, { "KMOD_GUI", SDL_KMOD_GUI },
|
||||
{ "KMOD_NONE", SDL_KMOD_NONE }, { "SDL_KMOD_LSHIFT", SDL_KMOD_LSHIFT },
|
||||
{ "SDL_KMOD_RSHIFT", SDL_KMOD_RSHIFT }, { "SDL_KMOD_LCTRL", SDL_KMOD_LCTRL },
|
||||
{ "SDL_KMOD_RCTRL", SDL_KMOD_RCTRL }, { "SDL_KMOD_LALT", SDL_KMOD_LALT },
|
||||
{ "SDL_KMOD_RALT", SDL_KMOD_RALT }, { "SDL_KMOD_LGUI", SDL_KMOD_LGUI },
|
||||
{ "SDL_KMOD_RGUI", SDL_KMOD_RGUI }, { "SDL_KMOD_NUM", SDL_KMOD_NUM },
|
||||
{ "SDL_KMOD_CAPS", SDL_KMOD_CAPS }, { "SDL_KMOD_MODE", SDL_KMOD_MODE },
|
||||
{ "SDL_KMOD_SCROLL", SDL_KMOD_SCROLL }, { "SDL_KMOD_CTRL", SDL_KMOD_CTRL },
|
||||
{ "SDL_KMOD_SHIFT", SDL_KMOD_SHIFT }, { "SDL_KMOD_ALT", SDL_KMOD_ALT },
|
||||
{ "SDL_KMOD_GUI", SDL_KMOD_GUI }, { "SDL_KMOD_NONE", SDL_KMOD_NONE }
|
||||
};
|
||||
|
||||
return s_map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::string modbyvalue(uint32_t val)
|
||||
{
|
||||
for (const auto& v : getSdlMap())
|
||||
{
|
||||
if (v.second == val)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
}
|
||||
return "KMOD_UNKNONW";
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::string masktostr(uint32_t mask)
|
||||
{
|
||||
if (mask == 0)
|
||||
return "<NONE>";
|
||||
|
||||
std::string str = "<";
|
||||
for (uint32_t x = 0; x < 32; x++)
|
||||
{
|
||||
uint32_t cmask = 1 << x;
|
||||
if ((mask & cmask) != 0)
|
||||
{
|
||||
auto s = modbyvalue(cmask);
|
||||
if (str.size() > 1)
|
||||
{
|
||||
str += ">+<";
|
||||
}
|
||||
str += s;
|
||||
}
|
||||
}
|
||||
str += ">";
|
||||
return str;
|
||||
}
|
||||
|
||||
bool sdlInput::prefToEnabled()
|
||||
{
|
||||
bool enabled = true;
|
||||
const auto& m = getSdlMap();
|
||||
for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
|
||||
{
|
||||
auto it = m.find(val);
|
||||
if (it != m.end())
|
||||
{
|
||||
if (it->second == SDL_KMOD_NONE)
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_WARN,
|
||||
"Invalid config::SDL_KeyModMask entry value '%s', disabling hotkeys",
|
||||
val.c_str());
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
uint32_t sdlInput::prefToMask()
|
||||
{
|
||||
const auto& m = getSdlMap();
|
||||
uint32_t mod = SDL_KMOD_NONE;
|
||||
for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
|
||||
{
|
||||
auto it = m.find(val);
|
||||
if (it != m.end())
|
||||
mod |= it->second;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const char* sdl_scancode_name(Uint32 scancode)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (cur.sdl == scancode)
|
||||
return cur.sdl_name;
|
||||
}
|
||||
|
||||
return "SDL_SCANCODE_UNKNOWN";
|
||||
}
|
||||
|
||||
[[nodiscard]] static Uint32 sdl_scancode_val(const char* scancodeName)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (strcmp(cur.sdl_name, scancodeName) == 0)
|
||||
return cur.sdl;
|
||||
}
|
||||
|
||||
return SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
|
||||
[[nodiscard]] static const char* sdl_rdp_scancode_name(UINT32 scancode)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (cur.rdp == scancode)
|
||||
return cur.rdp_name;
|
||||
}
|
||||
|
||||
return "RDP_SCANCODE_UNKNOWN";
|
||||
}
|
||||
|
||||
[[nodiscard]] static UINT32 sdl_rdp_scancode_val(const char* scancodeName)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (strcmp(cur.rdp_name, scancodeName) == 0)
|
||||
return cur.rdp;
|
||||
}
|
||||
|
||||
return RDP_SCANCODE_UNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
||||
UINT32 sdlInput::scancode_to_rdp(Uint32 scancode)
|
||||
{
|
||||
UINT32 rdp = RDP_SCANCODE_UNKNOWN;
|
||||
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (cur.sdl == scancode)
|
||||
{
|
||||
rdp = cur.rdp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
|
||||
auto code = static_cast<SDL_Scancode>(scancode);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_DEBUG, "got %s [%s] -> [%s]", SDL_GetScancodeName(code),
|
||||
sdl_scancode_name(scancode), sdl_rdp_scancode_name(rdp));
|
||||
#endif
|
||||
return rdp;
|
||||
}
|
||||
|
||||
uint32_t sdlInput::prefKeyValue(const std::string& key, uint32_t fallback)
|
||||
{
|
||||
auto item = SdlPref::instance()->get_string(key);
|
||||
if (item.empty())
|
||||
return fallback;
|
||||
auto val = sdl_scancode_val(item.c_str());
|
||||
if (val == SDL_SCANCODE_UNKNOWN)
|
||||
return fallback;
|
||||
return val;
|
||||
}
|
||||
|
||||
std::list<std::string> sdlInput::tokenize(const std::string& data, const std::string& delimiter)
|
||||
{
|
||||
size_t lastpos = 0;
|
||||
size_t pos = 0;
|
||||
std::list<std::string> list;
|
||||
while ((pos = data.find(delimiter, lastpos)) != std::string::npos)
|
||||
{
|
||||
auto token = data.substr(lastpos, pos);
|
||||
lastpos = pos + 1;
|
||||
list.push_back(std::move(token));
|
||||
}
|
||||
auto token = data.substr(lastpos);
|
||||
list.push_back(std::move(token));
|
||||
return list;
|
||||
}
|
||||
|
||||
bool sdlInput::extract(const std::string& token, uint32_t& key, uint32_t& value)
|
||||
{
|
||||
return freerdp_extract_key_value(token.c_str(), &key, &value);
|
||||
}
|
||||
|
||||
bool sdlInput::handleEvent(const SDL_KeyboardEvent& ev)
|
||||
{
|
||||
const UINT32 rdp_scancode = scancode_to_rdp(ev.scancode);
|
||||
const SDL_Keymod mods = SDL_GetModState();
|
||||
|
||||
if (_hotkeysEnabled && (mods & _hotkeyModmask) == _hotkeyModmask)
|
||||
{
|
||||
if (ev.type == SDL_EVENT_KEY_DOWN)
|
||||
{
|
||||
if (ev.scancode == _hotkeyFullscreen)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling fullscreen state",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyFullscreen));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return _sdl->toggleFullscreen();
|
||||
}
|
||||
if (ev.scancode == _hotkeyResizable)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling resizeable state",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyResizable));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return _sdl->toggleResizeable();
|
||||
}
|
||||
|
||||
if (ev.scancode == _hotkeyGrab)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling grab state",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyGrab));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return keyboard_grab(ev.windowID, !_sdl->grabKeyboard());
|
||||
}
|
||||
if (ev.scancode == _hotkeyDisconnect)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, disconnecting RDP session",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyDisconnect));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
freerdp_abort_connect_context(_sdl->context());
|
||||
return true;
|
||||
}
|
||||
if (ev.scancode == _hotkeyMinimize)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, minimizing client",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyMinimize));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return _sdl->setMinimized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_KBD)
|
||||
{
|
||||
const BOOL ex = RDP_SCANCODE_EXTENDED(rdp_scancode);
|
||||
const DWORD sc = RDP_SCANCODE_CODE(rdp_scancode);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
|
||||
"SDL keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s",
|
||||
ev.scancode, rdp_scancode, sc, ex ? " extended" : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
auto scancode = freerdp_keyboard_remap_key(_remapTable, rdp_scancode);
|
||||
#if defined(WITH_DEBUG_KBD)
|
||||
{
|
||||
const BOOL ex = RDP_SCANCODE_EXTENDED(scancode);
|
||||
const DWORD sc = RDP_SCANCODE_CODE(scancode);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
|
||||
"SDL keycode: %02" PRIX32 " -> remapped rdp code: [%04" PRIx16 "] %02" PRIX8
|
||||
"%s",
|
||||
ev.scancode, scancode, sc, ex ? " extended" : "");
|
||||
}
|
||||
#endif
|
||||
return freerdp_input_send_keyboard_event_ex(_sdl->context()->input,
|
||||
ev.type == SDL_EVENT_KEY_DOWN, ev.repeat, scancode);
|
||||
}
|
||||
|
||||
bool sdlInput::keyboard_grab(Uint32 windowID, bool enable)
|
||||
{
|
||||
const auto window = _sdl->getWindowForId(windowID);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
auto settings = _sdl->context()->settings;
|
||||
auto kbd_enabled = freerdp_settings_get_bool(settings, FreeRDP_GrabKeyboard);
|
||||
auto status = enable && kbd_enabled;
|
||||
if (!_sdl->setGrabKeyboard(status))
|
||||
WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab keyboard");
|
||||
return window->grabKeyboard(status);
|
||||
}
|
||||
|
||||
bool sdlInput::mouse_focus(Uint32 windowID)
|
||||
{
|
||||
if (_lastWindowID != windowID)
|
||||
{
|
||||
_lastWindowID = windowID;
|
||||
auto window = _sdl->getWindowForId(windowID);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
window->raise();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdlInput::mouse_grab(Uint32 windowID, bool enable)
|
||||
{
|
||||
auto window = _sdl->getWindowForId(windowID);
|
||||
if (!window)
|
||||
return false;
|
||||
if (!_sdl->setGrabMouse(enable))
|
||||
WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab mouse");
|
||||
return window->grabMouse(enable);
|
||||
}
|
||||
|
||||
sdlInput::sdlInput(SdlContext* sdl)
|
||||
: _sdl(sdl), _lastWindowID(UINT32_MAX), _hotkeysEnabled(prefToEnabled()),
|
||||
_hotkeyModmask(prefToMask())
|
||||
{
|
||||
_hotkeyFullscreen = prefKeyValue("SDL_Fullscreen", SDL_SCANCODE_RETURN);
|
||||
_hotkeyResizable = prefKeyValue("SDL_Resizeable", SDL_SCANCODE_R);
|
||||
_hotkeyGrab = prefKeyValue("SDL_Grab", SDL_SCANCODE_G);
|
||||
_hotkeyDisconnect = prefKeyValue("SDL_Disconnect", SDL_SCANCODE_D);
|
||||
_hotkeyMinimize = prefKeyValue("SDL_Minimize", SDL_SCANCODE_M);
|
||||
}
|
||||
|
||||
sdlInput::~sdlInput()
|
||||
{
|
||||
freerdp_keyboard_remap_free(_remapTable);
|
||||
}
|
||||
|
||||
bool sdlInput::initialize()
|
||||
{
|
||||
auto settings = _sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
WINPR_ASSERT(!_remapTable);
|
||||
|
||||
{
|
||||
auto list = freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList);
|
||||
_remapTable = freerdp_keyboard_remap_string_to_list(list);
|
||||
if (!_remapTable)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout) == 0)
|
||||
{
|
||||
DWORD KeyboardLayout = 0;
|
||||
|
||||
freerdp_detect_keyboard_layout_from_system_locale(&KeyboardLayout);
|
||||
if (KeyboardLayout == 0)
|
||||
KeyboardLayout = ENGLISH_UNITED_STATES;
|
||||
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, KeyboardLayout))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
84
third_party/FreeRDP/client/SDL/SDL3/sdl_input.hpp
vendored
Normal file
84
third_party/FreeRDP/client/SDL/SDL3/sdl_input.hpp
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client keyboard helper
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <atomic>
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_types.hpp"
|
||||
|
||||
class sdlInput
|
||||
{
|
||||
public:
|
||||
explicit sdlInput(SdlContext* sdl);
|
||||
sdlInput(const sdlInput& other) = delete;
|
||||
sdlInput(sdlInput&& other) = delete;
|
||||
virtual ~sdlInput();
|
||||
|
||||
sdlInput& operator=(const sdlInput& other) = delete;
|
||||
sdlInput& operator=(sdlInput&& other) = delete;
|
||||
|
||||
[[nodiscard]] bool initialize();
|
||||
|
||||
[[nodiscard]] bool keyboard_sync_state();
|
||||
[[nodiscard]] bool keyboard_focus_in();
|
||||
|
||||
[[nodiscard]] bool handleEvent(const SDL_KeyboardEvent& ev);
|
||||
|
||||
[[nodiscard]] bool keyboard_grab(Uint32 windowID, bool enable);
|
||||
[[nodiscard]] bool mouse_focus(Uint32 windowID);
|
||||
[[nodiscard]] bool mouse_grab(Uint32 windowID, bool enable);
|
||||
|
||||
[[nodiscard]] static BOOL keyboard_set_indicators(rdpContext* context, UINT16 led_flags);
|
||||
[[nodiscard]] static BOOL keyboard_set_ime_status(rdpContext* context, UINT16 imeId,
|
||||
UINT32 imeState, UINT32 imeConvMode);
|
||||
|
||||
[[nodiscard]] bool prefToEnabled();
|
||||
[[nodiscard]] uint32_t prefToMask();
|
||||
[[nodiscard]] static uint32_t prefKeyValue(const std::string& key,
|
||||
uint32_t fallback = SDL_SCANCODE_UNKNOWN);
|
||||
|
||||
private:
|
||||
[[nodiscard]] static std::list<std::string> tokenize(const std::string& data,
|
||||
const std::string& delimiter = ",");
|
||||
[[nodiscard]] static bool extract(const std::string& token, uint32_t& key, uint32_t& value);
|
||||
|
||||
[[nodiscard]] UINT32 scancode_to_rdp(Uint32 scancode);
|
||||
|
||||
SdlContext* _sdl = nullptr;
|
||||
Uint32 _lastWindowID = 0;
|
||||
|
||||
// hotkey handling
|
||||
bool _hotkeysEnabled = false;
|
||||
uint32_t _hotkeyModmask = 0; // modifier keys mask
|
||||
uint32_t _hotkeyFullscreen = 0;
|
||||
uint32_t _hotkeyResizable = 0;
|
||||
uint32_t _hotkeyGrab = 0;
|
||||
uint32_t _hotkeyDisconnect = 0;
|
||||
uint32_t _hotkeyMinimize = 0;
|
||||
FREERDP_REMAP_TABLE* _remapTable = nullptr;
|
||||
};
|
||||
311
third_party/FreeRDP/client/SDL/SDL3/sdl_monitor.cpp
vendored
Normal file
311
third_party/FreeRDP/client/SDL/SDL3/sdl_monitor.cpp
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Monitor Handling
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2017 David Fort <contact@hardening-consulting.com>
|
||||
* Copyright 2018 Kai Harms <kharms@rangee.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#define TAG CLIENT_TAG("sdl")
|
||||
|
||||
#include "sdl_monitor.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RECTANGLE_16 area;
|
||||
RECTANGLE_16 workarea;
|
||||
BOOL primary;
|
||||
} MONITOR_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int nmonitors;
|
||||
RECTANGLE_16 area;
|
||||
RECTANGLE_16 workarea;
|
||||
MONITOR_INFO* monitors;
|
||||
} VIRTUAL_SCREEN;
|
||||
|
||||
/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071
|
||||
*/
|
||||
|
||||
int sdl_list_monitors([[maybe_unused]] SdlContext* sdl)
|
||||
{
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
int nmonitors = 0;
|
||||
auto ids = SDL_GetDisplays(&nmonitors);
|
||||
|
||||
printf("listing %d monitors:\n", nmonitors);
|
||||
for (int i = 0; i < nmonitors; i++)
|
||||
{
|
||||
SDL_Rect rect = {};
|
||||
auto id = ids[i];
|
||||
const auto brc = SDL_GetDisplayBounds(id, &rect);
|
||||
const char* name = SDL_GetDisplayName(id);
|
||||
|
||||
if (!brc)
|
||||
continue;
|
||||
printf(" %s [%u] [%s] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", id, name, rect.w, rect.h,
|
||||
rect.x, rect.y);
|
||||
}
|
||||
SDL_free(ids);
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_apply_mon_max_size(SdlContext* sdl, UINT32* pMaxWidth,
|
||||
UINT32* pMaxHeight)
|
||||
{
|
||||
int32_t left = 0;
|
||||
int32_t right = 0;
|
||||
int32_t top = 0;
|
||||
int32_t bottom = 0;
|
||||
|
||||
WINPR_ASSERT(pMaxWidth);
|
||||
WINPR_ASSERT(pMaxHeight);
|
||||
|
||||
auto settings = sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
for (size_t x = 0; x < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); x++)
|
||||
{
|
||||
auto monitor = static_cast<const rdpMonitor*>(
|
||||
freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
|
||||
|
||||
left = std::min(monitor->x, left);
|
||||
top = std::min(monitor->y, top);
|
||||
right = std::max(monitor->x + monitor->width, right);
|
||||
bottom = std::max(monitor->y + monitor->height, bottom);
|
||||
}
|
||||
|
||||
const int32_t w = right - left;
|
||||
const int32_t h = bottom - top;
|
||||
|
||||
*pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, w);
|
||||
*pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, h);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_apply_max_size(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
WINPR_ASSERT(pMaxWidth);
|
||||
WINPR_ASSERT(pMaxHeight);
|
||||
|
||||
auto settings = sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
*pMaxWidth = 0;
|
||||
*pMaxHeight = 0;
|
||||
|
||||
for (size_t x = 0; x < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); x++)
|
||||
{
|
||||
auto monitor = static_cast<const rdpMonitor*>(
|
||||
freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
|
||||
{
|
||||
*pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
|
||||
*pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
|
||||
}
|
||||
else if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
|
||||
{
|
||||
SDL_Rect rect = {};
|
||||
SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
|
||||
*pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
|
||||
*pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
|
||||
}
|
||||
else if (freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen) > 0)
|
||||
{
|
||||
SDL_Rect rect = {};
|
||||
SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
|
||||
|
||||
*pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
|
||||
*pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth))
|
||||
*pMaxWidth = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.w) *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight))
|
||||
*pMaxHeight = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.h) *
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) /
|
||||
100;
|
||||
}
|
||||
else if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) &&
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight))
|
||||
{
|
||||
*pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
|
||||
*pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_apply_display_properties(SdlContext* sdl)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
rdpSettings* settings = sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
std::vector<rdpMonitor> monitors;
|
||||
if (!freerdp_settings_get_bool(settings, FreeRDP_Fullscreen) &&
|
||||
!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon))
|
||||
{
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_Workarea))
|
||||
{
|
||||
if (sdl->monitorIds().empty())
|
||||
return FALSE;
|
||||
const auto id = sdl->monitorIds().front();
|
||||
auto monitor = sdl->getDisplay(id);
|
||||
monitor.is_primary = true;
|
||||
monitor.x = 0;
|
||||
monitor.y = 0;
|
||||
monitors.emplace_back(monitor);
|
||||
return freerdp_settings_set_monitor_def_array_sorted(settings, monitors.data(),
|
||||
monitors.size());
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
for (const auto& id : sdl->monitorIds())
|
||||
{
|
||||
const auto monitor = sdl->getDisplay(id);
|
||||
monitors.emplace_back(monitor);
|
||||
}
|
||||
return freerdp_settings_set_monitor_def_array_sorted(settings, monitors.data(),
|
||||
monitors.size());
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_detect_single_window(SdlContext* sdl, UINT32* pMaxWidth,
|
||||
UINT32* pMaxHeight)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
WINPR_ASSERT(pMaxWidth);
|
||||
WINPR_ASSERT(pMaxHeight);
|
||||
|
||||
rdpSettings* settings = sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
if ((!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon) &&
|
||||
!freerdp_settings_get_bool(settings, FreeRDP_SpanMonitors)) ||
|
||||
(freerdp_settings_get_bool(settings, FreeRDP_Workarea) &&
|
||||
!freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode)))
|
||||
{
|
||||
/* If no monitors were specified on the command-line then set the current monitor as active
|
||||
*/
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 0)
|
||||
{
|
||||
SDL_DisplayID id = 0;
|
||||
const auto& ids = sdl->monitorIds();
|
||||
if (!ids.empty())
|
||||
{
|
||||
id = ids.front();
|
||||
}
|
||||
sdl->setMonitorIds({ id });
|
||||
}
|
||||
|
||||
if (!sdl_apply_display_properties(sdl))
|
||||
return FALSE;
|
||||
return sdl_apply_max_size(sdl, pMaxWidth, pMaxHeight);
|
||||
}
|
||||
return sdl_apply_mon_max_size(sdl, pMaxWidth, pMaxHeight);
|
||||
}
|
||||
|
||||
BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
WINPR_ASSERT(pMaxWidth);
|
||||
WINPR_ASSERT(pMaxHeight);
|
||||
|
||||
rdpSettings* settings = sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
const auto& ids = sdl->getDisplayIds();
|
||||
auto nr = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
|
||||
if (nr == 0)
|
||||
{
|
||||
if (freerdp_settings_get_bool(settings, FreeRDP_UseMultimon))
|
||||
sdl->setMonitorIds(ids);
|
||||
else
|
||||
{
|
||||
sdl->setMonitorIds({ ids.front() });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There were more IDs supplied than there are monitors */
|
||||
if (nr > ids.size())
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"Found %" PRIu32 " monitor IDs, but only have %" PRIuz " monitors connected",
|
||||
nr, ids.size());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::vector<SDL_DisplayID> used;
|
||||
for (size_t x = 0; x < nr; x++)
|
||||
{
|
||||
auto cur = static_cast<const UINT32*>(
|
||||
freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x));
|
||||
WINPR_ASSERT(cur);
|
||||
|
||||
SDL_DisplayID id = *cur;
|
||||
|
||||
/* the ID is no valid monitor index */
|
||||
if (std::find(ids.begin(), ids.end(), id) == ids.end())
|
||||
{
|
||||
WLog_ERR(TAG, "Supplied monitor ID[%" PRIuz "]=%" PRIu32 " is invalid", x, id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The ID is already taken */
|
||||
if (std::find(used.begin(), used.end(), id) != used.end())
|
||||
{
|
||||
WLog_ERR(TAG, "Duplicate monitor ID[%" PRIuz "]=%" PRIu32 " detected", x, id);
|
||||
return FALSE;
|
||||
}
|
||||
used.push_back(id);
|
||||
}
|
||||
sdl->setMonitorIds(used);
|
||||
}
|
||||
|
||||
if (!sdl_apply_display_properties(sdl))
|
||||
return FALSE;
|
||||
|
||||
auto size = static_cast<uint32_t>(sdl->monitorIds().size());
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, size))
|
||||
return FALSE;
|
||||
|
||||
return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight);
|
||||
}
|
||||
28
third_party/FreeRDP/client/SDL/SDL3/sdl_monitor.hpp
vendored
Normal file
28
third_party/FreeRDP/client/SDL/SDL3/sdl_monitor.hpp
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Monitor Handling
|
||||
*
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#include "sdl_types.hpp"
|
||||
|
||||
[[nodiscard]] int sdl_list_monitors(SdlContext* sdl);
|
||||
[[nodiscard]] BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pMaxWidth, UINT32* ppMaxHeight);
|
||||
254
third_party/FreeRDP/client/SDL/SDL3/sdl_pointer.cpp
vendored
Normal file
254
third_party/FreeRDP/client/SDL/SDL3/sdl_pointer.cpp
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Wayland Mouse Pointer
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
|
||||
#include "sdl_pointer.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
#include "sdl_touch.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#include <SDL3/SDL_mouse.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rdpPointer pointer;
|
||||
SDL_Cursor* cursor;
|
||||
SDL_Surface* image;
|
||||
size_t size;
|
||||
void* data;
|
||||
} sdlPointer;
|
||||
|
||||
[[nodiscard]] static BOOL sdl_Pointer_New(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
auto ptr = reinterpret_cast<sdlPointer*>(pointer);
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
if (!ptr)
|
||||
return FALSE;
|
||||
|
||||
rdpGdi* gdi = context->gdi;
|
||||
WINPR_ASSERT(gdi);
|
||||
|
||||
ptr->size = 4ull * pointer->width * pointer->height;
|
||||
ptr->data = winpr_aligned_malloc(ptr->size, 16);
|
||||
|
||||
if (!ptr->data)
|
||||
return FALSE;
|
||||
|
||||
auto data = static_cast<BYTE*>(ptr->data);
|
||||
if (!freerdp_image_copy_from_pointer_data(
|
||||
data, gdi->dstFormat, 0, 0, 0, pointer->width, pointer->height, pointer->xorMaskData,
|
||||
pointer->lengthXorMask, pointer->andMaskData, pointer->lengthAndMask, pointer->xorBpp,
|
||||
&context->gdi->palette))
|
||||
{
|
||||
winpr_aligned_free(ptr->data);
|
||||
ptr->data = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void sdl_Pointer_Clear(sdlPointer* ptr)
|
||||
{
|
||||
WINPR_ASSERT(ptr);
|
||||
SDL_DestroyCursor(ptr->cursor);
|
||||
SDL_DestroySurface(ptr->image);
|
||||
ptr->cursor = nullptr;
|
||||
ptr->image = nullptr;
|
||||
}
|
||||
|
||||
static void sdl_Pointer_Free(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
auto ptr = reinterpret_cast<sdlPointer*>(pointer);
|
||||
WINPR_UNUSED(context);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
sdl_Pointer_Clear(ptr);
|
||||
winpr_aligned_free(ptr->data);
|
||||
ptr->data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_Pointer_SetDefault(rdpContext* context)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
|
||||
return sdl_push_user_event(SDL_EVENT_USER_POINTER_DEFAULT);
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_Pointer_Set(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
return sdl_push_user_event(SDL_EVENT_USER_POINTER_SET, pointer);
|
||||
}
|
||||
|
||||
bool sdl_Pointer_Set_Process(SdlContext* sdl)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
auto context = sdl->context();
|
||||
auto pointer = sdl->cursor();
|
||||
auto ptr = reinterpret_cast<sdlPointer*>(pointer);
|
||||
if (!ptr)
|
||||
return true;
|
||||
|
||||
rdpGdi* gdi = context->gdi;
|
||||
WINPR_ASSERT(gdi);
|
||||
|
||||
auto ix = static_cast<float>(pointer->xPos);
|
||||
auto iy = static_cast<float>(pointer->yPos);
|
||||
auto isw = static_cast<float>(pointer->width);
|
||||
auto ish = static_cast<float>(pointer->height);
|
||||
|
||||
auto window = SDL_GetMouseFocus();
|
||||
if (!window)
|
||||
return sdl_Pointer_SetDefault(context);
|
||||
|
||||
const Uint32 id = SDL_GetWindowID(window);
|
||||
|
||||
const SDL_FRect orig{ ix, iy, isw, ish };
|
||||
auto pos = sdl->pixelToScreen(id, orig);
|
||||
WLog_Print(sdl->getWLog(), WLOG_DEBUG, "cursor scale: pixel:%s, display:%s",
|
||||
sdl::utils::toString(orig).c_str(), sdl::utils::toString(pos).c_str());
|
||||
|
||||
sdl_Pointer_Clear(ptr);
|
||||
|
||||
ptr->image =
|
||||
SDL_CreateSurface(static_cast<int>(orig.w), static_cast<int>(orig.h), sdl->pixelFormat());
|
||||
if (!ptr->image)
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_CreateSurface failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SDL_LockSurface(ptr->image))
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_LockSurface failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pixels = static_cast<BYTE*>(ptr->image->pixels);
|
||||
auto data = static_cast<const BYTE*>(ptr->data);
|
||||
const BOOL rc = freerdp_image_scale(
|
||||
pixels, gdi->dstFormat, static_cast<UINT32>(ptr->image->pitch), 0, 0,
|
||||
static_cast<UINT32>(ptr->image->w), static_cast<UINT32>(ptr->image->h), data,
|
||||
gdi->dstFormat, 0, 0, 0, static_cast<UINT32>(isw), static_cast<UINT32>(ish));
|
||||
SDL_UnlockSurface(ptr->image);
|
||||
if (!rc)
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "freerdp_image_scale failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// create a cursor image in 100% display scale to trick SDL into creating the cursor with the
|
||||
// correct size
|
||||
auto fw = sdl->getFirstWindow();
|
||||
if (!fw)
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "sdl->getFirstWindow() nullptr");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto hidpi_scale =
|
||||
sdl->pixelToScreen(fw->id(), SDL_FPoint{ static_cast<float>(ptr->image->w),
|
||||
static_cast<float>(ptr->image->h) });
|
||||
std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)> normal{
|
||||
SDL_CreateSurface(static_cast<int>(hidpi_scale.x), static_cast<int>(hidpi_scale.y),
|
||||
ptr->image->format),
|
||||
SDL_DestroySurface
|
||||
};
|
||||
assert(normal);
|
||||
if (!SDL_BlitSurfaceScaled(ptr->image, nullptr, normal.get(), nullptr,
|
||||
SDL_ScaleMode::SDL_SCALEMODE_LINEAR))
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_BlitSurfaceScaled failed");
|
||||
return false;
|
||||
}
|
||||
if (!SDL_AddSurfaceAlternateImage(normal.get(), ptr->image))
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_AddSurfaceAlternateImage failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ptr->cursor =
|
||||
SDL_CreateColorCursor(normal.get(), static_cast<int>(pos.x), static_cast<int>(pos.y));
|
||||
if (!ptr->cursor)
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_CreateColorCursor(display:%s, pixel:%s} failed",
|
||||
sdl::utils::toString(pos).c_str(), sdl::utils::toString(orig).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SDL_SetCursor(ptr->cursor))
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_SetCursor failed");
|
||||
return false;
|
||||
}
|
||||
if (!SDL_ShowCursor())
|
||||
{
|
||||
WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_ShowCursor failed");
|
||||
return false;
|
||||
}
|
||||
sdl->setHasCursor(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_Pointer_SetNull(rdpContext* context)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
|
||||
return sdl_push_user_event(SDL_EVENT_USER_POINTER_NULL);
|
||||
}
|
||||
|
||||
[[nodiscard]] static BOOL sdl_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
return sdl_push_user_event(SDL_EVENT_USER_POINTER_POSITION, x, y);
|
||||
}
|
||||
|
||||
bool sdl_register_pointer(rdpGraphics* graphics)
|
||||
{
|
||||
const rdpPointer pointer = { sizeof(sdlPointer),
|
||||
sdl_Pointer_New,
|
||||
sdl_Pointer_Free,
|
||||
sdl_Pointer_Set,
|
||||
sdl_Pointer_SetNull,
|
||||
sdl_Pointer_SetDefault,
|
||||
sdl_Pointer_SetPosition,
|
||||
{},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{} };
|
||||
graphics_register_pointer(graphics, &pointer);
|
||||
return true;
|
||||
}
|
||||
30
third_party/FreeRDP/client/SDL/SDL3/sdl_pointer.hpp
vendored
Normal file
30
third_party/FreeRDP/client/SDL/SDL3/sdl_pointer.hpp
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Mouse Pointer
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "sdl_types.hpp"
|
||||
|
||||
#include <freerdp/graphics.h>
|
||||
|
||||
[[nodiscard]] bool sdl_register_pointer(rdpGraphics* graphics);
|
||||
|
||||
[[nodiscard]] bool sdl_Pointer_Set_Process(SdlContext* sdl);
|
||||
208
third_party/FreeRDP/client/SDL/SDL3/sdl_touch.cpp
vendored
Normal file
208
third_party/FreeRDP/client/SDL/SDL3/sdl_touch.cpp
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP SDL touch/mouse input
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include "sdl_touch.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
[[nodiscard]] static bool send_mouse_wheel(SdlContext* sdl, UINT16 flags, INT32 avalue)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
if (avalue < 0)
|
||||
{
|
||||
flags |= PTR_FLAGS_WHEEL_NEGATIVE;
|
||||
avalue = -avalue;
|
||||
}
|
||||
|
||||
while (avalue > 0)
|
||||
{
|
||||
const UINT16 cval = (avalue > 0xFF) ? 0xFF : static_cast<UINT16>(avalue);
|
||||
UINT16 cflags = flags | cval;
|
||||
/* Convert negative values to 9bit twos complement */
|
||||
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
|
||||
cflags = (flags & 0xFF00) | (0x100 - cval);
|
||||
if (!freerdp_client_send_wheel_event(sdl->common(), cflags))
|
||||
return FALSE;
|
||||
|
||||
avalue -= cval;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
[[nodiscard]] static UINT32 sdl_scale_pressure(const float pressure)
|
||||
{
|
||||
const float val = pressure * 0x400; /* [MS-RDPEI] 2.2.3.3.1.1 RDPINPUT_TOUCH_CONTACT */
|
||||
if (val < 0.0f)
|
||||
return 0;
|
||||
if (val > 0x400)
|
||||
return 0x400;
|
||||
return static_cast<UINT32>(val);
|
||||
}
|
||||
|
||||
bool SdlTouch::touchUp(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
return freerdp_client_handle_touch(sdl->common(), FREERDP_TOUCH_UP | FREERDP_TOUCH_HAS_PRESSURE,
|
||||
static_cast<INT32>(ev.fingerID),
|
||||
sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
|
||||
static_cast<Sint32>(ev.y));
|
||||
}
|
||||
|
||||
bool SdlTouch::touchCancel(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
return freerdp_client_handle_touch(
|
||||
sdl->common(), FREERDP_TOUCH_CANCEL | FREERDP_TOUCH_HAS_PRESSURE,
|
||||
static_cast<INT32>(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
|
||||
static_cast<Sint32>(ev.y));
|
||||
}
|
||||
|
||||
bool SdlTouch::touchDown(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
return freerdp_client_handle_touch(
|
||||
sdl->common(), FREERDP_TOUCH_DOWN | FREERDP_TOUCH_HAS_PRESSURE,
|
||||
static_cast<INT32>(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
|
||||
static_cast<Sint32>(ev.y));
|
||||
}
|
||||
|
||||
bool SdlTouch::touchMotion(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
return freerdp_client_handle_touch(
|
||||
sdl->common(), FREERDP_TOUCH_MOTION | FREERDP_TOUCH_HAS_PRESSURE,
|
||||
static_cast<INT32>(ev.fingerID), sdl_scale_pressure(ev.pressure), static_cast<Sint32>(ev.x),
|
||||
static_cast<Sint32>(ev.y));
|
||||
}
|
||||
|
||||
bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseMotionEvent& ev)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
if (!sdl->getInputChannelContext().mouse_focus(ev.windowID))
|
||||
return FALSE;
|
||||
|
||||
const BOOL relative =
|
||||
freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor();
|
||||
auto x = static_cast<INT32>(relative ? ev.xrel : ev.x);
|
||||
auto y = static_cast<INT32>(relative ? ev.yrel : ev.y);
|
||||
return freerdp_client_send_button_event(sdl->common(), relative, PTR_FLAGS_MOVE, x, y);
|
||||
}
|
||||
|
||||
bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseWheelEvent& ev)
|
||||
{
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
const BOOL flipped = (ev.direction == SDL_MOUSEWHEEL_FLIPPED);
|
||||
const auto x = static_cast<INT32>(ev.x * (flipped ? -1.0f : 1.0f) * 120.0f);
|
||||
const auto y = static_cast<INT32>(ev.y * (flipped ? -1.0f : 1.0f) * 120.0f);
|
||||
UINT16 flags = 0;
|
||||
|
||||
if (y != 0)
|
||||
{
|
||||
flags |= PTR_FLAGS_WHEEL;
|
||||
if (!send_mouse_wheel(sdl, flags, y))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x != 0)
|
||||
{
|
||||
flags |= PTR_FLAGS_HWHEEL;
|
||||
if (!send_mouse_wheel(sdl, flags, x))
|
||||
return false;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_MouseButtonEvent& ev)
|
||||
{
|
||||
UINT16 flags = 0;
|
||||
UINT16 xflags = 0;
|
||||
|
||||
WINPR_ASSERT(sdl);
|
||||
|
||||
if (ev.type == SDL_EVENT_MOUSE_BUTTON_DOWN)
|
||||
{
|
||||
flags |= PTR_FLAGS_DOWN;
|
||||
xflags |= PTR_XFLAGS_DOWN;
|
||||
}
|
||||
|
||||
switch (ev.button)
|
||||
{
|
||||
case 1:
|
||||
flags |= PTR_FLAGS_BUTTON1;
|
||||
break;
|
||||
case 2:
|
||||
flags |= PTR_FLAGS_BUTTON3;
|
||||
break;
|
||||
case 3:
|
||||
flags |= PTR_FLAGS_BUTTON2;
|
||||
break;
|
||||
case 4:
|
||||
xflags |= PTR_XFLAGS_BUTTON1;
|
||||
break;
|
||||
case 5:
|
||||
xflags |= PTR_XFLAGS_BUTTON2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const BOOL relative =
|
||||
freerdp_client_use_relative_mouse_events(sdl->common()) && !sdl->hasCursor();
|
||||
auto x = static_cast<INT32>(relative ? 0 : ev.x);
|
||||
auto y = static_cast<INT32>(relative ? 0 : ev.y);
|
||||
|
||||
if ((flags & (~PTR_FLAGS_DOWN)) != 0)
|
||||
return freerdp_client_send_button_event(sdl->common(), relative, flags, x, y);
|
||||
else if ((xflags & (~PTR_XFLAGS_DOWN)) != 0)
|
||||
return freerdp_client_send_extended_button_event(sdl->common(), relative, xflags, x, y);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool SdlTouch::handleEvent(SdlContext* sdl, const SDL_TouchFingerEvent& ev)
|
||||
{
|
||||
switch (ev.type)
|
||||
{
|
||||
case SDL_EVENT_FINGER_CANCELED:
|
||||
return SdlTouch::touchCancel(sdl, ev);
|
||||
case SDL_EVENT_FINGER_UP:
|
||||
return SdlTouch::touchUp(sdl, ev);
|
||||
case SDL_EVENT_FINGER_DOWN:
|
||||
return SdlTouch::touchDown(sdl, ev);
|
||||
case SDL_EVENT_FINGER_MOTION:
|
||||
return SdlTouch::touchMotion(sdl, ev);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
41
third_party/FreeRDP/client/SDL/SDL3/sdl_touch.hpp
vendored
Normal file
41
third_party/FreeRDP/client/SDL/SDL3/sdl_touch.hpp
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP SDL touch/mouse input
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include "sdl_types.hpp"
|
||||
|
||||
class SdlTouch
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static bool handleEvent(SdlContext* sdl, const SDL_MouseMotionEvent& ev);
|
||||
[[nodiscard]] static bool handleEvent(SdlContext* sdl, const SDL_MouseWheelEvent& ev);
|
||||
[[nodiscard]] static bool handleEvent(SdlContext* sdl, const SDL_MouseButtonEvent& ev);
|
||||
|
||||
[[nodiscard]] static bool handleEvent(SdlContext* sdl, const SDL_TouchFingerEvent& ev);
|
||||
|
||||
private:
|
||||
[[nodiscard]] static bool touchDown(SdlContext* sdl, const SDL_TouchFingerEvent& ev);
|
||||
[[nodiscard]] static bool touchUp(SdlContext* sdl, const SDL_TouchFingerEvent& ev);
|
||||
[[nodiscard]] static bool touchCancel(SdlContext* sdl, const SDL_TouchFingerEvent& ev);
|
||||
[[nodiscard]] static bool touchMotion(SdlContext* sdl, const SDL_TouchFingerEvent& ev);
|
||||
};
|
||||
46
third_party/FreeRDP/client/SDL/SDL3/sdl_types.hpp
vendored
Normal file
46
third_party/FreeRDP/client/SDL/SDL3/sdl_types.hpp
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
class SdlContext;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rdpClientContext common;
|
||||
SdlContext* sdl;
|
||||
} sdl_rdp_context;
|
||||
|
||||
[[nodiscard]] static inline SdlContext* get_context(void* ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return nullptr;
|
||||
auto sdl = static_cast<sdl_rdp_context*>(ctx);
|
||||
return sdl->sdl;
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline SdlContext* get_context(rdpContext* ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return nullptr;
|
||||
auto sdl = reinterpret_cast<sdl_rdp_context*>(ctx);
|
||||
return sdl->sdl;
|
||||
}
|
||||
610
third_party/FreeRDP/client/SDL/SDL3/sdl_utils.cpp
vendored
Normal file
610
third_party/FreeRDP/client/SDL/SDL3/sdl_utils.cpp
vendored
Normal file
@@ -0,0 +1,610 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#include "sdl_freerdp.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <freerdp/version.h>
|
||||
#include <freerdp/utils/string.h>
|
||||
|
||||
#define STR(x) #x
|
||||
#define EV_CASE_STR(x) \
|
||||
case x: \
|
||||
return STR(x)
|
||||
|
||||
const char* sdl_error_string(Sint32 res)
|
||||
{
|
||||
if (res == 0)
|
||||
return nullptr;
|
||||
|
||||
return SDL_GetError();
|
||||
}
|
||||
|
||||
BOOL sdl_log_error_ex(Sint32 res, wLog* log, const char* what, const char* file, size_t line,
|
||||
const char* fkt)
|
||||
{
|
||||
const char* msg = sdl_error_string(res);
|
||||
|
||||
WINPR_UNUSED(file);
|
||||
|
||||
if (!msg)
|
||||
return FALSE;
|
||||
|
||||
WLog_Print(log, WLOG_ERROR, "[%s:%" PRIuz "][%s]: %s", fkt, line, what, msg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool sdl_push_user_event(Uint32 type, ...)
|
||||
{
|
||||
SDL_Event ev = {};
|
||||
SDL_UserEvent* event = &ev.user;
|
||||
|
||||
va_list ap = {};
|
||||
va_start(ap, type);
|
||||
event->type = type;
|
||||
switch (type)
|
||||
{
|
||||
case SDL_EVENT_USER_AUTH_RESULT:
|
||||
{
|
||||
auto arg = reinterpret_cast<SDL_UserAuthArg*>(ev.padding);
|
||||
arg->user = va_arg(ap, char*);
|
||||
arg->domain = va_arg(ap, char*);
|
||||
arg->password = va_arg(ap, char*);
|
||||
arg->result = va_arg(ap, Sint32);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_AUTH_DIALOG:
|
||||
{
|
||||
auto arg = reinterpret_cast<SDL_UserAuthArg*>(ev.padding);
|
||||
|
||||
arg->title = va_arg(ap, char*);
|
||||
arg->user = va_arg(ap, char*);
|
||||
arg->domain = va_arg(ap, char*);
|
||||
arg->password = va_arg(ap, char*);
|
||||
arg->result = va_arg(ap, Sint32);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_SCARD_DIALOG:
|
||||
{
|
||||
event->data1 = va_arg(ap, char*);
|
||||
event->data2 = va_arg(ap, char**);
|
||||
event->code = va_arg(ap, Sint32);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_USER_RETRY_DIALOG:
|
||||
event->code = va_arg(ap, Sint32);
|
||||
break;
|
||||
case SDL_EVENT_USER_SCARD_RESULT:
|
||||
case SDL_EVENT_USER_SHOW_RESULT:
|
||||
case SDL_EVENT_USER_CERT_RESULT:
|
||||
event->code = va_arg(ap, Sint32);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_USER_SHOW_DIALOG:
|
||||
event->data1 = va_arg(ap, char*);
|
||||
event->data2 = va_arg(ap, char*);
|
||||
event->code = va_arg(ap, Sint32);
|
||||
break;
|
||||
case SDL_EVENT_USER_CERT_DIALOG:
|
||||
event->data1 = va_arg(ap, char*);
|
||||
event->data2 = va_arg(ap, char*);
|
||||
break;
|
||||
case SDL_EVENT_USER_UPDATE:
|
||||
event->data1 = va_arg(ap, void*);
|
||||
break;
|
||||
case SDL_EVENT_USER_POINTER_POSITION:
|
||||
event->data1 = reinterpret_cast<void*>(static_cast<uintptr_t>(va_arg(ap, UINT32)));
|
||||
event->data2 = reinterpret_cast<void*>(static_cast<uintptr_t>(va_arg(ap, UINT32)));
|
||||
break;
|
||||
case SDL_EVENT_USER_POINTER_SET:
|
||||
event->data1 = va_arg(ap, void*);
|
||||
event->data2 = va_arg(ap, void*);
|
||||
break;
|
||||
case SDL_EVENT_USER_CREATE_WINDOWS:
|
||||
event->data1 = va_arg(ap, void*);
|
||||
break;
|
||||
case SDL_EVENT_USER_WINDOW_FULLSCREEN:
|
||||
event->data1 = va_arg(ap, void*);
|
||||
event->code = va_arg(ap, int);
|
||||
event->data2 = reinterpret_cast<void*>(static_cast<uintptr_t>(va_arg(ap, int)));
|
||||
break;
|
||||
case SDL_EVENT_USER_WINDOW_RESIZEABLE:
|
||||
event->data1 = va_arg(ap, void*);
|
||||
event->code = va_arg(ap, int);
|
||||
break;
|
||||
case SDL_EVENT_USER_WINDOW_MINIMIZE:
|
||||
case SDL_EVENT_USER_QUIT:
|
||||
case SDL_EVENT_USER_POINTER_NULL:
|
||||
case SDL_EVENT_USER_POINTER_DEFAULT:
|
||||
case SDL_EVENT_CLIPBOARD_UPDATE:
|
||||
break;
|
||||
default:
|
||||
va_end(ap);
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] unsupported type %u", __func__, type);
|
||||
return false;
|
||||
}
|
||||
va_end(ap);
|
||||
const auto rc = SDL_PushEvent(&ev);
|
||||
if (rc != 1)
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "[%s] SDL_PushEvent returned %d", __func__, rc);
|
||||
return rc == 1;
|
||||
}
|
||||
|
||||
bool sdl_push_quit()
|
||||
{
|
||||
SDL_Event ev = {};
|
||||
ev.type = SDL_EVENT_QUIT;
|
||||
SDL_PushEvent(&ev);
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace sdl::utils
|
||||
{
|
||||
UINT32 orientaion_to_rdp(SDL_DisplayOrientation orientation)
|
||||
{
|
||||
switch (orientation)
|
||||
{
|
||||
case SDL_ORIENTATION_LANDSCAPE:
|
||||
return ORIENTATION_LANDSCAPE;
|
||||
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
|
||||
return ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
|
||||
return ORIENTATION_PORTRAIT_FLIPPED;
|
||||
case SDL_ORIENTATION_PORTRAIT:
|
||||
default:
|
||||
return ORIENTATION_PORTRAIT;
|
||||
}
|
||||
}
|
||||
|
||||
std::string touchFlagsToString(Uint32 flags)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{";
|
||||
bool first = true;
|
||||
for (size_t x = 0; x < 32; x++)
|
||||
{
|
||||
const Uint32 mask = 1u << x;
|
||||
if (flags & mask)
|
||||
{
|
||||
if (!first)
|
||||
ss << "|";
|
||||
first = false;
|
||||
ss << freerdp_input_touch_state_string(mask);
|
||||
}
|
||||
}
|
||||
ss << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(SDL_DisplayOrientation orientation)
|
||||
{
|
||||
switch (orientation)
|
||||
{
|
||||
case SDL_ORIENTATION_LANDSCAPE:
|
||||
return "SDL_ORIENTATION_LANDSCAPE";
|
||||
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
|
||||
return "SDL_ORIENTATION_LANDSCAPE_FLIPPED";
|
||||
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
|
||||
return "SDL_ORIENTATION_PORTRAIT_FLIPPED";
|
||||
case SDL_ORIENTATION_PORTRAIT:
|
||||
return "SDL_ORIENTATION_PORTRAIT";
|
||||
default:
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SDL_ORIENTATION_UNKNOWN[0x" << std::hex << std::setw(8) << std::setfill('0')
|
||||
<< orientation << "]";
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string toString(FreeRDP_DesktopRotationFlags orientation)
|
||||
{
|
||||
return freerdp_desktop_rotation_flags_to_string(orientation);
|
||||
}
|
||||
|
||||
std::string toString(const SDL_DisplayMode* mode)
|
||||
{
|
||||
if (!mode)
|
||||
return "SDL_DisplayMode=null";
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "["
|
||||
<< "id=" << mode->displayID << ","
|
||||
<< "fmt=" << mode->format << ","
|
||||
<< "w=" << mode->w << ","
|
||||
<< "h=" << mode->h << ","
|
||||
<< "dpi=" << mode->pixel_density << ","
|
||||
<< "refresh=" << mode->refresh_rate << ","
|
||||
<< "num=" << mode->refresh_rate_numerator << ","
|
||||
<< "denom=" << mode->refresh_rate_denominator << "]";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(Uint32 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
EV_CASE_STR(SDL_EVENT_FIRST);
|
||||
EV_CASE_STR(SDL_EVENT_QUIT);
|
||||
EV_CASE_STR(SDL_EVENT_TERMINATING);
|
||||
EV_CASE_STR(SDL_EVENT_LOW_MEMORY);
|
||||
EV_CASE_STR(SDL_EVENT_WILL_ENTER_BACKGROUND);
|
||||
EV_CASE_STR(SDL_EVENT_DID_ENTER_BACKGROUND);
|
||||
EV_CASE_STR(SDL_EVENT_WILL_ENTER_FOREGROUND);
|
||||
EV_CASE_STR(SDL_EVENT_DID_ENTER_FOREGROUND);
|
||||
EV_CASE_STR(SDL_EVENT_LOCALE_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_SYSTEM_THEME_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_DISPLAY_ORIENTATION);
|
||||
EV_CASE_STR(SDL_EVENT_DISPLAY_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_DISPLAY_REMOVED);
|
||||
EV_CASE_STR(SDL_EVENT_DISPLAY_MOVED);
|
||||
EV_CASE_STR(SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_SHOWN);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_HIDDEN);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_EXPOSED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_MOVED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_RESIZED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_MINIMIZED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_MAXIMIZED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_RESTORED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_MOUSE_ENTER);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_MOUSE_LEAVE);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_FOCUS_GAINED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_FOCUS_LOST);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_CLOSE_REQUESTED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_HIT_TEST);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_ICCPROF_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_DISPLAY_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_SAFE_AREA_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_OCCLUDED);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_ENTER_FULLSCREEN);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_LEAVE_FULLSCREEN);
|
||||
EV_CASE_STR(SDL_EVENT_WINDOW_DESTROYED);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_KEY_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_KEY_UP);
|
||||
EV_CASE_STR(SDL_EVENT_TEXT_EDITING);
|
||||
EV_CASE_STR(SDL_EVENT_TEXT_INPUT);
|
||||
EV_CASE_STR(SDL_EVENT_KEYMAP_CHANGED);
|
||||
EV_CASE_STR(SDL_EVENT_KEYBOARD_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_KEYBOARD_REMOVED);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_MOUSE_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_MOUSE_BUTTON_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_MOUSE_BUTTON_UP);
|
||||
EV_CASE_STR(SDL_EVENT_MOUSE_WHEEL);
|
||||
EV_CASE_STR(SDL_EVENT_MOUSE_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_MOUSE_REMOVED);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_AXIS_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_BALL_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_HAT_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_BUTTON_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_BUTTON_UP);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_REMOVED);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_BATTERY_UPDATED);
|
||||
EV_CASE_STR(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_AXIS_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_BUTTON_UP);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_REMOVED);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_REMAPPED);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_TOUCHPAD_UP);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_SENSOR_UPDATE);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_UPDATE_COMPLETE);
|
||||
EV_CASE_STR(SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_FINGER_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_FINGER_UP);
|
||||
EV_CASE_STR(SDL_EVENT_FINGER_MOTION);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_CLIPBOARD_UPDATE);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_DROP_FILE);
|
||||
EV_CASE_STR(SDL_EVENT_DROP_TEXT);
|
||||
EV_CASE_STR(SDL_EVENT_DROP_BEGIN);
|
||||
EV_CASE_STR(SDL_EVENT_DROP_COMPLETE);
|
||||
EV_CASE_STR(SDL_EVENT_DROP_POSITION);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_AUDIO_DEVICE_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_AUDIO_DEVICE_REMOVED);
|
||||
EV_CASE_STR(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_SENSOR_UPDATE);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_PEN_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_PEN_UP);
|
||||
EV_CASE_STR(SDL_EVENT_PEN_MOTION);
|
||||
EV_CASE_STR(SDL_EVENT_PEN_BUTTON_DOWN);
|
||||
EV_CASE_STR(SDL_EVENT_PEN_BUTTON_UP);
|
||||
EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_ADDED);
|
||||
EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_REMOVED);
|
||||
EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_APPROVED);
|
||||
EV_CASE_STR(SDL_EVENT_CAMERA_DEVICE_DENIED);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_RENDER_TARGETS_RESET);
|
||||
EV_CASE_STR(SDL_EVENT_RENDER_DEVICE_RESET);
|
||||
EV_CASE_STR(SDL_EVENT_POLL_SENTINEL);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_USER);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_USER_CERT_DIALOG);
|
||||
EV_CASE_STR(SDL_EVENT_USER_CERT_RESULT);
|
||||
EV_CASE_STR(SDL_EVENT_USER_SHOW_DIALOG);
|
||||
EV_CASE_STR(SDL_EVENT_USER_SHOW_RESULT);
|
||||
EV_CASE_STR(SDL_EVENT_USER_AUTH_DIALOG);
|
||||
EV_CASE_STR(SDL_EVENT_USER_AUTH_RESULT);
|
||||
EV_CASE_STR(SDL_EVENT_USER_SCARD_DIALOG);
|
||||
EV_CASE_STR(SDL_EVENT_USER_RETRY_DIALOG);
|
||||
EV_CASE_STR(SDL_EVENT_USER_SCARD_RESULT);
|
||||
EV_CASE_STR(SDL_EVENT_USER_UPDATE);
|
||||
EV_CASE_STR(SDL_EVENT_USER_CREATE_WINDOWS);
|
||||
EV_CASE_STR(SDL_EVENT_USER_WINDOW_RESIZEABLE);
|
||||
EV_CASE_STR(SDL_EVENT_USER_WINDOW_FULLSCREEN);
|
||||
EV_CASE_STR(SDL_EVENT_USER_WINDOW_MINIMIZE);
|
||||
EV_CASE_STR(SDL_EVENT_USER_POINTER_NULL);
|
||||
EV_CASE_STR(SDL_EVENT_USER_POINTER_DEFAULT);
|
||||
EV_CASE_STR(SDL_EVENT_USER_POINTER_POSITION);
|
||||
EV_CASE_STR(SDL_EVENT_USER_POINTER_SET);
|
||||
EV_CASE_STR(SDL_EVENT_USER_QUIT);
|
||||
|
||||
EV_CASE_STR(SDL_EVENT_LAST);
|
||||
default:
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SDL_UNKNOWNEVENT[0x" << std::hex << std::setw(8) << std::setfill('0') << type
|
||||
<< "]";
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string generate_uuid_v4()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static std::uniform_int_distribution<> dis(0, 255);
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setfill('0') << std::setw(2);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
ss << dis(gen);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
HighDpiScaleMode platformScaleMode()
|
||||
{
|
||||
const auto platform = SDL_GetPlatform();
|
||||
if (!platform)
|
||||
return SCALE_MODE_INVALID;
|
||||
if (strcmp("Windows", platform) == 0)
|
||||
return SCALE_MODE_X11;
|
||||
if (strcmp("macOS", platform) == 0)
|
||||
return SCALE_MODE_WAYLAND;
|
||||
if (strcmp("Linux", platform) == 0)
|
||||
{
|
||||
const auto driver = SDL_GetCurrentVideoDriver();
|
||||
if (!driver)
|
||||
return SCALE_MODE_WAYLAND;
|
||||
if (strcmp("x11", driver) == 0)
|
||||
return SCALE_MODE_X11;
|
||||
if (strcmp("wayland", driver) == 0)
|
||||
return SCALE_MODE_WAYLAND;
|
||||
}
|
||||
return SCALE_MODE_INVALID;
|
||||
}
|
||||
|
||||
std::string windowTitle(const rdpSettings* settings)
|
||||
{
|
||||
const char* prefix = "FreeRDP:";
|
||||
|
||||
if (!settings)
|
||||
return {};
|
||||
|
||||
const auto windowTitle = freerdp_settings_get_string(settings, FreeRDP_WindowTitle);
|
||||
if (windowTitle)
|
||||
return {};
|
||||
|
||||
const auto name = freerdp_settings_get_server_name(settings);
|
||||
const auto port = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
|
||||
|
||||
const auto addPort = (port != 3389);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << prefix << " ";
|
||||
if (!addPort)
|
||||
ss << name;
|
||||
else
|
||||
ss << name << ":" << port;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(SDL_Rect rect)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SDL_Rect{" << rect.x << "x" << rect.y << "-" << rect.w << "x" << rect.h << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string toString(SDL_FRect rect)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "SDL_Rect{" << rect.x << "x" << rect.y << "-" << rect.w << "x" << rect.h << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace sdl::utils
|
||||
|
||||
namespace sdl::error
|
||||
{
|
||||
struct sdl_exitCode_map_t
|
||||
{
|
||||
DWORD error;
|
||||
int code;
|
||||
const char* code_tag;
|
||||
};
|
||||
|
||||
#define ENTRY(x, y) { x, y, #y }
|
||||
static const struct sdl_exitCode_map_t sdl_exitCode_map[] = {
|
||||
ENTRY(FREERDP_ERROR_SUCCESS, SUCCESS), ENTRY(FREERDP_ERROR_NONE, DISCONNECT),
|
||||
ENTRY(FREERDP_ERROR_NONE, LOGOFF), ENTRY(FREERDP_ERROR_NONE, IDLE_TIMEOUT),
|
||||
ENTRY(FREERDP_ERROR_NONE, LOGON_TIMEOUT), ENTRY(FREERDP_ERROR_NONE, CONN_REPLACED),
|
||||
ENTRY(FREERDP_ERROR_NONE, OUT_OF_MEMORY), ENTRY(FREERDP_ERROR_NONE, CONN_DENIED),
|
||||
ENTRY(FREERDP_ERROR_NONE, CONN_DENIED_FIPS), ENTRY(FREERDP_ERROR_NONE, USER_PRIVILEGES),
|
||||
ENTRY(FREERDP_ERROR_NONE, FRESH_CREDENTIALS_REQUIRED),
|
||||
ENTRY(ERRINFO_LOGOFF_BY_USER, DISCONNECT_BY_USER), ENTRY(FREERDP_ERROR_NONE, UNKNOWN),
|
||||
|
||||
/* section 16-31: license error set */
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_INTERNAL),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_NO_LICENSE_SERVER),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_NO_LICENSE),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_BAD_CLIENT_MSG),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_HWID_DOESNT_MATCH),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_BAD_CLIENT),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_CANT_FINISH_PROTOCOL),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_CLIENT_ENDED_PROTOCOL),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_BAD_CLIENT_ENCRYPTION),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_CANT_UPGRADE),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_NO_REMOTE_CONNECTIONS),
|
||||
ENTRY(FREERDP_ERROR_NONE, LICENSE_CANT_UPGRADE),
|
||||
|
||||
/* section 32-127: RDP protocol error set */
|
||||
ENTRY(FREERDP_ERROR_NONE, RDP),
|
||||
|
||||
/* section 128-254: xfreerdp specific exit codes */
|
||||
ENTRY(FREERDP_ERROR_NONE, PARSE_ARGUMENTS), ENTRY(FREERDP_ERROR_NONE, MEMORY),
|
||||
ENTRY(FREERDP_ERROR_NONE, PROTOCOL), ENTRY(FREERDP_ERROR_NONE, CONN_FAILED),
|
||||
|
||||
ENTRY(FREERDP_ERROR_AUTHENTICATION_FAILED, AUTH_FAILURE),
|
||||
ENTRY(FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED, NEGO_FAILURE),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_LOGON_FAILURE, LOGON_FAILURE),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_TARGET_BOOTING, CONNECT_TARGET_BOOTING),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT, ACCOUNT_LOCKED_OUT),
|
||||
ENTRY(FREERDP_ERROR_PRE_CONNECT_FAILED, PRE_CONNECT_FAILED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_UNDEFINED, CONNECT_UNDEFINED),
|
||||
ENTRY(FREERDP_ERROR_POST_CONNECT_FAILED, POST_CONNECT_FAILED),
|
||||
ENTRY(FREERDP_ERROR_DNS_ERROR, DNS_ERROR),
|
||||
ENTRY(FREERDP_ERROR_DNS_NAME_NOT_FOUND, DNS_NAME_NOT_FOUND),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_FAILED, CONNECT_FAILED),
|
||||
ENTRY(FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR, MCS_CONNECT_INITIAL_ERROR),
|
||||
ENTRY(FREERDP_ERROR_TLS_CONNECT_FAILED, TLS_CONNECT_FAILED),
|
||||
ENTRY(FREERDP_ERROR_INSUFFICIENT_PRIVILEGES, INSUFFICIENT_PRIVILEGES),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_CANCELLED, CONNECT_CANCELLED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_TRANSPORT_FAILED, CONNECT_TRANSPORT_FAILED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED, CONNECT_PASSWORD_EXPIRED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE, CONNECT_PASSWORD_MUST_CHANGE),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_KDC_UNREACHABLE, CONNECT_KDC_UNREACHABLE),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED, CONNECT_ACCOUNT_DISABLED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED, CONNECT_PASSWORD_CERTAINLY_EXPIRED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_CLIENT_REVOKED, CONNECT_CLIENT_REVOKED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_WRONG_PASSWORD, CONNECT_WRONG_PASSWORD),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_ACCESS_DENIED, CONNECT_ACCESS_DENIED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION, CONNECT_ACCOUNT_RESTRICTION),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED, CONNECT_ACCOUNT_EXPIRED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED, CONNECT_LOGON_TYPE_NOT_GRANTED),
|
||||
ENTRY(FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS, CONNECT_NO_OR_MISSING_CREDENTIALS)
|
||||
};
|
||||
|
||||
static const sdl_exitCode_map_t* mapEntryByCode(int exit_code)
|
||||
{
|
||||
for (const auto& x : sdl_exitCode_map)
|
||||
{
|
||||
auto cur = &x;
|
||||
if (cur->code == exit_code)
|
||||
return cur;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const sdl_exitCode_map_t* mapEntryByError(UINT32 error)
|
||||
{
|
||||
for (const auto& x : sdl_exitCode_map)
|
||||
{
|
||||
auto cur = &x;
|
||||
if (cur->error == error)
|
||||
return cur;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int errorToExitCode(DWORD error)
|
||||
{
|
||||
auto entry = mapEntryByError(error);
|
||||
if (entry)
|
||||
return entry->code;
|
||||
|
||||
return CONN_FAILED;
|
||||
}
|
||||
|
||||
const char* errorToExitCodeTag(UINT32 error)
|
||||
{
|
||||
auto entry = mapEntryByError(error);
|
||||
if (entry)
|
||||
return entry->code_tag;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* exitCodeToTag(int code)
|
||||
{
|
||||
auto entry = mapEntryByCode(code);
|
||||
if (entry)
|
||||
return entry->code_tag;
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace sdl::error
|
||||
184
third_party/FreeRDP/client/SDL/SDL3/sdl_utils.hpp
vendored
Normal file
184
third_party/FreeRDP/client/SDL/SDL3/sdl_utils.hpp
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include <sdl_common_utils.hpp>
|
||||
|
||||
template <typename T> using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T*)>>;
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_EVENT_USER_UPDATE = SDL_EVENT_USER + 1,
|
||||
SDL_EVENT_USER_CREATE_WINDOWS,
|
||||
SDL_EVENT_USER_WINDOW_RESIZEABLE,
|
||||
SDL_EVENT_USER_WINDOW_FULLSCREEN,
|
||||
SDL_EVENT_USER_WINDOW_MINIMIZE,
|
||||
SDL_EVENT_USER_POINTER_NULL,
|
||||
SDL_EVENT_USER_POINTER_DEFAULT,
|
||||
SDL_EVENT_USER_POINTER_POSITION,
|
||||
SDL_EVENT_USER_POINTER_SET,
|
||||
SDL_EVENT_USER_QUIT,
|
||||
SDL_EVENT_USER_CERT_DIALOG,
|
||||
SDL_EVENT_USER_SHOW_DIALOG,
|
||||
SDL_EVENT_USER_AUTH_DIALOG,
|
||||
SDL_EVENT_USER_SCARD_DIALOG,
|
||||
SDL_EVENT_USER_RETRY_DIALOG,
|
||||
|
||||
SDL_EVENT_USER_CERT_RESULT,
|
||||
SDL_EVENT_USER_SHOW_RESULT,
|
||||
SDL_EVENT_USER_AUTH_RESULT,
|
||||
SDL_EVENT_USER_SCARD_RESULT
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint32 type;
|
||||
Uint32 timestamp;
|
||||
char* title;
|
||||
char* user;
|
||||
char* domain;
|
||||
char* password;
|
||||
Sint32 result;
|
||||
} SDL_UserAuthArg;
|
||||
|
||||
[[nodiscard]] bool sdl_push_user_event(Uint32 type, ...);
|
||||
|
||||
[[nodiscard]] bool sdl_push_quit();
|
||||
|
||||
[[nodiscard]] const char* sdl_error_string(Sint32 res);
|
||||
|
||||
#define sdl_log_error(res, log, what) sdl_log_error_ex(res, log, what, __FILE__, __LINE__, __func__)
|
||||
[[nodiscard]] BOOL sdl_log_error_ex(Sint32 res, wLog* log, const char* what, const char* file,
|
||||
size_t line, const char* fkt);
|
||||
|
||||
namespace sdl::utils
|
||||
{
|
||||
[[nodiscard]] std::string touchFlagsToString(Uint32 flags);
|
||||
[[nodiscard]] std::string toString(enum FreeRDP_DesktopRotationFlags orientation);
|
||||
[[nodiscard]] std::string toString(SDL_DisplayOrientation orientation);
|
||||
[[nodiscard]] std::string toString(const SDL_DisplayMode* mode);
|
||||
[[nodiscard]] std::string toString(Uint32 type);
|
||||
[[nodiscard]] std::string toString(SDL_Rect rect);
|
||||
[[nodiscard]] std::string toString(SDL_FRect rect);
|
||||
|
||||
[[nodiscard]] UINT32 orientaion_to_rdp(SDL_DisplayOrientation orientation);
|
||||
|
||||
[[nodiscard]] std::string generate_uuid_v4();
|
||||
|
||||
enum HighDpiScaleMode
|
||||
{
|
||||
SCALE_MODE_INVALID,
|
||||
SCALE_MODE_X11,
|
||||
SCALE_MODE_WAYLAND
|
||||
};
|
||||
|
||||
[[nodiscard]] HighDpiScaleMode platformScaleMode();
|
||||
|
||||
[[nodiscard]] std::string windowTitle(const rdpSettings* settings);
|
||||
|
||||
} // namespace sdl::utils
|
||||
|
||||
namespace sdl::error
|
||||
{
|
||||
enum EXIT_CODE
|
||||
{
|
||||
/* section 0-15: protocol-independent codes */
|
||||
SUCCESS = 0,
|
||||
DISCONNECT = 1,
|
||||
LOGOFF = 2,
|
||||
IDLE_TIMEOUT = 3,
|
||||
LOGON_TIMEOUT = 4,
|
||||
CONN_REPLACED = 5,
|
||||
OUT_OF_MEMORY = 6,
|
||||
CONN_DENIED = 7,
|
||||
CONN_DENIED_FIPS = 8,
|
||||
USER_PRIVILEGES = 9,
|
||||
FRESH_CREDENTIALS_REQUIRED = 10,
|
||||
DISCONNECT_BY_USER = 11,
|
||||
|
||||
/* section 16-31: license error set */
|
||||
LICENSE_INTERNAL = 16,
|
||||
LICENSE_NO_LICENSE_SERVER = 17,
|
||||
LICENSE_NO_LICENSE = 18,
|
||||
LICENSE_BAD_CLIENT_MSG = 19,
|
||||
LICENSE_HWID_DOESNT_MATCH = 20,
|
||||
LICENSE_BAD_CLIENT = 21,
|
||||
LICENSE_CANT_FINISH_PROTOCOL = 22,
|
||||
LICENSE_CLIENT_ENDED_PROTOCOL = 23,
|
||||
LICENSE_BAD_CLIENT_ENCRYPTION = 24,
|
||||
LICENSE_CANT_UPGRADE = 25,
|
||||
LICENSE_NO_REMOTE_CONNECTIONS = 26,
|
||||
|
||||
/* section 32-127: RDP protocol error set */
|
||||
RDP = 32,
|
||||
|
||||
/* section 128-254: xfreerdp specific exit codes */
|
||||
PARSE_ARGUMENTS = 128,
|
||||
MEMORY = 129,
|
||||
PROTOCOL = 130,
|
||||
CONN_FAILED = 131,
|
||||
AUTH_FAILURE = 132,
|
||||
NEGO_FAILURE = 133,
|
||||
LOGON_FAILURE = 134,
|
||||
ACCOUNT_LOCKED_OUT = 135,
|
||||
PRE_CONNECT_FAILED = 136,
|
||||
CONNECT_UNDEFINED = 137,
|
||||
POST_CONNECT_FAILED = 138,
|
||||
DNS_ERROR = 139,
|
||||
DNS_NAME_NOT_FOUND = 140,
|
||||
CONNECT_FAILED = 141,
|
||||
MCS_CONNECT_INITIAL_ERROR = 142,
|
||||
TLS_CONNECT_FAILED = 143,
|
||||
INSUFFICIENT_PRIVILEGES = 144,
|
||||
CONNECT_CANCELLED = 145,
|
||||
|
||||
CONNECT_TRANSPORT_FAILED = 147,
|
||||
CONNECT_PASSWORD_EXPIRED = 148,
|
||||
CONNECT_PASSWORD_MUST_CHANGE = 149,
|
||||
CONNECT_KDC_UNREACHABLE = 150,
|
||||
CONNECT_ACCOUNT_DISABLED = 151,
|
||||
CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152,
|
||||
CONNECT_CLIENT_REVOKED = 153,
|
||||
CONNECT_WRONG_PASSWORD = 154,
|
||||
CONNECT_ACCESS_DENIED = 155,
|
||||
CONNECT_ACCOUNT_RESTRICTION = 156,
|
||||
CONNECT_ACCOUNT_EXPIRED = 157,
|
||||
CONNECT_LOGON_TYPE_NOT_GRANTED = 158,
|
||||
CONNECT_NO_OR_MISSING_CREDENTIALS = 159,
|
||||
CONNECT_TARGET_BOOTING = 160,
|
||||
|
||||
UNKNOWN = 255,
|
||||
};
|
||||
|
||||
[[nodiscard]] int errorToExitCode(DWORD error);
|
||||
[[nodiscard]] const char* errorToExitCodeTag(UINT32 error);
|
||||
[[nodiscard]] const char* exitCodeToTag(int code);
|
||||
} // namespace sdl::error
|
||||
486
third_party/FreeRDP/client/SDL/SDL3/sdl_window.cpp
vendored
Normal file
486
third_party/FreeRDP/client/SDL/SDL3/sdl_window.cpp
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2023 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 <limits>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "sdl_window.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#include <freerdp/utils/string.h>
|
||||
|
||||
SdlWindow::SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect,
|
||||
[[maybe_unused]] Uint32 flags)
|
||||
: _displayID(id)
|
||||
{
|
||||
auto props = SDL_CreateProperties();
|
||||
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title.c_str());
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, rect.x);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, rect.y);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, rect.w);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, rect.h);
|
||||
|
||||
if (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||
|
||||
if (flags & SDL_WINDOW_FULLSCREEN)
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
|
||||
|
||||
if (flags & SDL_WINDOW_BORDERLESS)
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
|
||||
|
||||
_window = SDL_CreateWindowWithProperties(props);
|
||||
SDL_DestroyProperties(props);
|
||||
|
||||
auto sc = scale();
|
||||
const int iscale = static_cast<int>(sc * 100.0f);
|
||||
auto w = 100 * rect.w / iscale;
|
||||
auto h = 100 * rect.h / iscale;
|
||||
std::ignore = resize({ w, h });
|
||||
SDL_SetHint(SDL_HINT_APP_NAME, "");
|
||||
std::ignore = SDL_SyncWindow(_window);
|
||||
|
||||
_monitor = query(_window, id, true);
|
||||
}
|
||||
|
||||
SdlWindow::SdlWindow(SdlWindow&& other) noexcept
|
||||
: _window(other._window), _displayID(other._displayID), _offset_x(other._offset_x),
|
||||
_offset_y(other._offset_y), _monitor(other._monitor)
|
||||
{
|
||||
other._window = nullptr;
|
||||
}
|
||||
|
||||
SdlWindow::~SdlWindow()
|
||||
{
|
||||
SDL_DestroyWindow(_window);
|
||||
}
|
||||
|
||||
SDL_WindowID SdlWindow::id() const
|
||||
{
|
||||
if (!_window)
|
||||
return 0;
|
||||
return SDL_GetWindowID(_window);
|
||||
}
|
||||
|
||||
SDL_DisplayID SdlWindow::displayIndex() const
|
||||
{
|
||||
if (!_window)
|
||||
return 0;
|
||||
return SDL_GetDisplayForWindow(_window);
|
||||
}
|
||||
|
||||
SDL_Rect SdlWindow::rect() const
|
||||
{
|
||||
return rect(_window);
|
||||
}
|
||||
|
||||
SDL_Rect SdlWindow::bounds() const
|
||||
{
|
||||
SDL_Rect rect = {};
|
||||
if (_window)
|
||||
{
|
||||
if (!SDL_GetWindowPosition(_window, &rect.x, &rect.y))
|
||||
return {};
|
||||
if (!SDL_GetWindowSize(_window, &rect.w, &rect.h))
|
||||
return {};
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
SDL_Window* SdlWindow::window() const
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
Sint32 SdlWindow::offsetX() const
|
||||
{
|
||||
return _offset_x;
|
||||
}
|
||||
|
||||
void SdlWindow::setOffsetX(Sint32 x)
|
||||
{
|
||||
_offset_x = x;
|
||||
}
|
||||
|
||||
void SdlWindow::setOffsetY(Sint32 y)
|
||||
{
|
||||
_offset_y = y;
|
||||
}
|
||||
|
||||
Sint32 SdlWindow::offsetY() const
|
||||
{
|
||||
return _offset_y;
|
||||
}
|
||||
|
||||
rdpMonitor SdlWindow::monitor(bool isPrimary) const
|
||||
{
|
||||
auto m = _monitor;
|
||||
if (isPrimary)
|
||||
{
|
||||
m.x = 0;
|
||||
m.y = 0;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void SdlWindow::setMonitor(rdpMonitor monitor)
|
||||
{
|
||||
_monitor = monitor;
|
||||
}
|
||||
|
||||
float SdlWindow::scale() const
|
||||
{
|
||||
return SDL_GetWindowDisplayScale(_window);
|
||||
}
|
||||
|
||||
SDL_DisplayOrientation SdlWindow::orientation() const
|
||||
{
|
||||
const auto did = displayIndex();
|
||||
return SDL_GetCurrentDisplayOrientation(did);
|
||||
}
|
||||
|
||||
bool SdlWindow::grabKeyboard(bool enable)
|
||||
{
|
||||
if (!_window)
|
||||
return false;
|
||||
SDL_SetWindowKeyboardGrab(_window, enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlWindow::grabMouse(bool enable)
|
||||
{
|
||||
if (!_window)
|
||||
return false;
|
||||
SDL_SetWindowMouseGrab(_window, enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SdlWindow::setBordered(bool bordered)
|
||||
{
|
||||
if (_window)
|
||||
SDL_SetWindowBordered(_window, bordered);
|
||||
std::ignore = SDL_SyncWindow(_window);
|
||||
}
|
||||
|
||||
void SdlWindow::raise()
|
||||
{
|
||||
SDL_RaiseWindow(_window);
|
||||
std::ignore = SDL_SyncWindow(_window);
|
||||
}
|
||||
|
||||
void SdlWindow::resizeable(bool use)
|
||||
{
|
||||
SDL_SetWindowResizable(_window, use);
|
||||
std::ignore = SDL_SyncWindow(_window);
|
||||
}
|
||||
|
||||
void SdlWindow::fullscreen(bool enter, bool forceOriginalDisplay)
|
||||
{
|
||||
if (enter && forceOriginalDisplay && _displayID != 0)
|
||||
{
|
||||
/* Move the window to the desired display. We should not wait
|
||||
* for the window to be moved, because some backends can refuse
|
||||
* the move. The intent of moving the window is enough for SDL
|
||||
* to decide which display will be used for fullscreen. */
|
||||
SDL_Rect rect = {};
|
||||
std::ignore = SDL_GetDisplayBounds(_displayID, &rect);
|
||||
std::ignore = SDL_SetWindowPosition(_window, rect.x, rect.y);
|
||||
}
|
||||
std::ignore = SDL_SetWindowFullscreen(_window, enter);
|
||||
std::ignore = SDL_SyncWindow(_window);
|
||||
}
|
||||
|
||||
void SdlWindow::minimize()
|
||||
{
|
||||
SDL_MinimizeWindow(_window);
|
||||
std::ignore = SDL_SyncWindow(_window);
|
||||
}
|
||||
|
||||
bool SdlWindow::resize(const SDL_Point& size)
|
||||
{
|
||||
return SDL_SetWindowSize(_window, size.x, size.y);
|
||||
}
|
||||
|
||||
bool SdlWindow::drawRect(SDL_Surface* surface, SDL_Point offset, const SDL_Rect& srcRect)
|
||||
{
|
||||
WINPR_ASSERT(surface);
|
||||
SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
|
||||
return blit(surface, srcRect, dstRect);
|
||||
}
|
||||
|
||||
bool SdlWindow::drawRects(SDL_Surface* surface, SDL_Point offset,
|
||||
const std::vector<SDL_Rect>& rects)
|
||||
{
|
||||
if (rects.empty())
|
||||
{
|
||||
return drawRect(surface, offset, { 0, 0, surface->w, surface->h });
|
||||
}
|
||||
for (auto& srcRect : rects)
|
||||
{
|
||||
if (!drawRect(surface, offset, srcRect))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlWindow::drawScaledRect(SDL_Surface* surface, const SDL_FPoint& scale,
|
||||
const SDL_Rect& srcRect)
|
||||
{
|
||||
SDL_Rect dstRect = srcRect;
|
||||
dstRect.x = static_cast<Sint32>(static_cast<float>(dstRect.x) * scale.x);
|
||||
dstRect.w = static_cast<Sint32>(static_cast<float>(dstRect.w) * scale.x);
|
||||
dstRect.y = static_cast<Sint32>(static_cast<float>(dstRect.y) * scale.y);
|
||||
dstRect.h = static_cast<Sint32>(static_cast<float>(dstRect.h) * scale.y);
|
||||
return blit(surface, srcRect, dstRect);
|
||||
}
|
||||
|
||||
bool SdlWindow::drawScaledRects(SDL_Surface* surface, const SDL_FPoint& scale,
|
||||
const std::vector<SDL_Rect>& rects)
|
||||
{
|
||||
if (rects.empty())
|
||||
{
|
||||
return drawScaledRect(surface, scale, { 0, 0, surface->w, surface->h });
|
||||
}
|
||||
for (const auto& srcRect : rects)
|
||||
{
|
||||
if (!drawScaledRect(surface, scale, srcRect))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlWindow::fill(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
||||
{
|
||||
return fill(_window, r, g, b, a);
|
||||
}
|
||||
|
||||
bool SdlWindow::fill(SDL_Window* window, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
||||
{
|
||||
auto surface = SDL_GetWindowSurface(window);
|
||||
if (!surface)
|
||||
return false;
|
||||
SDL_Rect rect = { 0, 0, surface->w, surface->h };
|
||||
auto color = SDL_MapSurfaceRGBA(surface, r, g, b, a);
|
||||
|
||||
return SDL_FillSurfaceRect(surface, &rect, color);
|
||||
}
|
||||
|
||||
rdpMonitor SdlWindow::query(SDL_Window* window, SDL_DisplayID id, bool forceAsPrimary)
|
||||
{
|
||||
if (!window)
|
||||
return {};
|
||||
|
||||
const auto& r = rect(window, forceAsPrimary);
|
||||
const float factor = SDL_GetWindowDisplayScale(window);
|
||||
const float dpi = std::roundf(factor * 100.0f);
|
||||
|
||||
WINPR_ASSERT(r.w > 0);
|
||||
WINPR_ASSERT(r.h > 0);
|
||||
|
||||
const auto primary = SDL_GetPrimaryDisplay();
|
||||
const auto orientation = SDL_GetCurrentDisplayOrientation(id);
|
||||
const auto rdp_orientation = sdl::utils::orientaion_to_rdp(orientation);
|
||||
|
||||
rdpMonitor monitor{};
|
||||
monitor.orig_screen = id;
|
||||
monitor.x = r.x;
|
||||
monitor.y = r.y;
|
||||
monitor.width = r.w;
|
||||
monitor.height = r.h;
|
||||
monitor.is_primary = forceAsPrimary || (id == primary);
|
||||
monitor.attributes.desktopScaleFactor = static_cast<UINT32>(dpi);
|
||||
monitor.attributes.deviceScaleFactor = 100;
|
||||
monitor.attributes.orientation = rdp_orientation;
|
||||
monitor.attributes.physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, r.w);
|
||||
monitor.attributes.physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, r.h);
|
||||
|
||||
const auto cat = SDL_LOG_CATEGORY_APPLICATION;
|
||||
SDL_LogDebug(cat, "monitor.orig_screen %" PRIu32, monitor.orig_screen);
|
||||
SDL_LogDebug(cat, "monitor.x %" PRId32, monitor.x);
|
||||
SDL_LogDebug(cat, "monitor.y %" PRId32, monitor.y);
|
||||
SDL_LogDebug(cat, "monitor.width %" PRId32, monitor.width);
|
||||
SDL_LogDebug(cat, "monitor.height %" PRId32, monitor.height);
|
||||
SDL_LogDebug(cat, "monitor.is_primary %" PRIu32, monitor.is_primary);
|
||||
SDL_LogDebug(cat, "monitor.attributes.desktopScaleFactor %" PRIu32,
|
||||
monitor.attributes.desktopScaleFactor);
|
||||
SDL_LogDebug(cat, "monitor.attributes.deviceScaleFactor %" PRIu32,
|
||||
monitor.attributes.deviceScaleFactor);
|
||||
SDL_LogDebug(cat, "monitor.attributes.orientation %s",
|
||||
freerdp_desktop_rotation_flags_to_string(monitor.attributes.orientation));
|
||||
SDL_LogDebug(cat, "monitor.attributes.physicalWidth %" PRIu32,
|
||||
monitor.attributes.physicalWidth);
|
||||
SDL_LogDebug(cat, "monitor.attributes.physicalHeight %" PRIu32,
|
||||
monitor.attributes.physicalHeight);
|
||||
return monitor;
|
||||
}
|
||||
|
||||
SDL_Rect SdlWindow::rect(SDL_Window* window, bool forceAsPrimary)
|
||||
{
|
||||
SDL_Rect rect = {};
|
||||
if (!window)
|
||||
return {};
|
||||
|
||||
if (!forceAsPrimary)
|
||||
{
|
||||
if (!SDL_GetWindowPosition(window, &rect.x, &rect.y))
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!SDL_GetWindowSizeInPixels(window, &rect.w, &rect.h))
|
||||
return {};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
SdlWindow::HighDPIMode SdlWindow::isHighDPIWindowsMode(SDL_Window* window)
|
||||
{
|
||||
if (!window)
|
||||
return MODE_INVALID;
|
||||
|
||||
const auto id = SDL_GetDisplayForWindow(window);
|
||||
if (id == 0)
|
||||
return MODE_INVALID;
|
||||
|
||||
const auto cs = SDL_GetDisplayContentScale(id);
|
||||
const auto ds = SDL_GetWindowDisplayScale(window);
|
||||
const auto pd = SDL_GetWindowPixelDensity(window);
|
||||
|
||||
/* mac os x style, but no HighDPI display */
|
||||
if ((cs == 1.0f) && (ds == 1.0f) && (pd == 1.0f))
|
||||
return MODE_NONE;
|
||||
|
||||
/* mac os x style HighDPI */
|
||||
if ((cs == 1.0f) && (ds > 1.0f) && (pd > 1.0f))
|
||||
return MODE_MACOS;
|
||||
|
||||
/* rest is windows style */
|
||||
return MODE_WINDOWS;
|
||||
}
|
||||
|
||||
bool SdlWindow::blit(SDL_Surface* surface, const SDL_Rect& srcRect, SDL_Rect& dstRect)
|
||||
{
|
||||
auto screen = SDL_GetWindowSurface(_window);
|
||||
if (!screen || !surface)
|
||||
return false;
|
||||
if (!SDL_SetSurfaceClipRect(surface, &srcRect))
|
||||
return true;
|
||||
if (!SDL_SetSurfaceClipRect(screen, &dstRect))
|
||||
return true;
|
||||
if (!SDL_BlitSurfaceScaled(surface, &srcRect, screen, &dstRect, SDL_SCALEMODE_LINEAR))
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL_BlitScaled: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SdlWindow::updateSurface()
|
||||
{
|
||||
SDL_UpdateWindowSurface(_window);
|
||||
}
|
||||
|
||||
SdlWindow SdlWindow::create(SDL_DisplayID id, const std::string& title, Uint32 flags, Uint32 width,
|
||||
Uint32 height)
|
||||
{
|
||||
flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
|
||||
|
||||
SDL_Rect rect = { static_cast<int>(SDL_WINDOWPOS_CENTERED_DISPLAY(id)),
|
||||
static_cast<int>(SDL_WINDOWPOS_CENTERED_DISPLAY(id)), static_cast<int>(width),
|
||||
static_cast<int>(height) };
|
||||
|
||||
if ((flags & SDL_WINDOW_FULLSCREEN) != 0)
|
||||
{
|
||||
std::ignore = SDL_GetDisplayBounds(id, &rect);
|
||||
}
|
||||
|
||||
SdlWindow window{ id, title, rect, flags };
|
||||
|
||||
if ((flags & (SDL_WINDOW_FULLSCREEN)) != 0)
|
||||
{
|
||||
window.setOffsetX(rect.x);
|
||||
window.setOffsetY(rect.y);
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static SDL_Window* createDummy(SDL_DisplayID id)
|
||||
{
|
||||
const auto x = SDL_WINDOWPOS_CENTERED_DISPLAY(id);
|
||||
const auto y = SDL_WINDOWPOS_CENTERED_DISPLAY(id);
|
||||
const int w = 64;
|
||||
const int h = 64;
|
||||
|
||||
auto props = SDL_CreateProperties();
|
||||
std::stringstream ss;
|
||||
ss << "SdlWindow::query(" << id << ")";
|
||||
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, ss.str().c_str());
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w);
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h);
|
||||
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, false);
|
||||
|
||||
auto window = SDL_CreateWindowWithProperties(props);
|
||||
SDL_DestroyProperties(props);
|
||||
return window;
|
||||
}
|
||||
|
||||
rdpMonitor SdlWindow::query(SDL_DisplayID id, bool forceAsPrimary)
|
||||
{
|
||||
std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> window(createDummy(id), SDL_DestroyWindow);
|
||||
if (!window)
|
||||
return {};
|
||||
|
||||
std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> renderer(
|
||||
SDL_CreateRenderer(window.get(), nullptr), SDL_DestroyRenderer);
|
||||
|
||||
if (!SDL_SyncWindow(window.get()))
|
||||
return {};
|
||||
|
||||
SDL_Event event{};
|
||||
while (SDL_PollEvent(&event))
|
||||
;
|
||||
|
||||
return query(window.get(), id, forceAsPrimary);
|
||||
}
|
||||
|
||||
SDL_Rect SdlWindow::rect(SDL_DisplayID id, bool forceAsPrimary)
|
||||
{
|
||||
std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> window(createDummy(id), SDL_DestroyWindow);
|
||||
if (!window)
|
||||
return {};
|
||||
|
||||
std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> renderer(
|
||||
SDL_CreateRenderer(window.get(), nullptr), SDL_DestroyRenderer);
|
||||
|
||||
if (!SDL_SyncWindow(window.get()))
|
||||
return {};
|
||||
|
||||
SDL_Event event{};
|
||||
while (SDL_PollEvent(&event))
|
||||
;
|
||||
|
||||
return rect(window.get(), forceAsPrimary);
|
||||
}
|
||||
110
third_party/FreeRDP/client/SDL/SDL3/sdl_window.hpp
vendored
Normal file
110
third_party/FreeRDP/client/SDL/SDL3/sdl_window.hpp
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* SDL Client
|
||||
*
|
||||
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <freerdp/settings_types.h>
|
||||
|
||||
class SdlWindow
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] static SdlWindow create(SDL_DisplayID id, const std::string& title, Uint32 flags,
|
||||
Uint32 width = 0, Uint32 height = 0);
|
||||
[[nodiscard]] static rdpMonitor query(SDL_DisplayID id, bool forceAsPrimary = false);
|
||||
|
||||
SdlWindow(SdlWindow&& other) noexcept;
|
||||
SdlWindow(const SdlWindow& other) = delete;
|
||||
virtual ~SdlWindow();
|
||||
|
||||
SdlWindow& operator=(const SdlWindow& other) = delete;
|
||||
SdlWindow& operator=(SdlWindow&& other) = delete;
|
||||
|
||||
[[nodiscard]] SDL_WindowID id() const;
|
||||
[[nodiscard]] SDL_DisplayID displayIndex() const;
|
||||
[[nodiscard]] SDL_Rect rect() const;
|
||||
[[nodiscard]] SDL_Rect bounds() const;
|
||||
[[nodiscard]] SDL_Window* window() const;
|
||||
|
||||
[[nodiscard]] Sint32 offsetX() const;
|
||||
void setOffsetX(Sint32 x);
|
||||
|
||||
void setOffsetY(Sint32 y);
|
||||
[[nodiscard]] Sint32 offsetY() const;
|
||||
|
||||
[[nodiscard]] rdpMonitor monitor(bool isPrimary) const;
|
||||
void setMonitor(rdpMonitor monitor);
|
||||
|
||||
[[nodiscard]] float scale() const;
|
||||
[[nodiscard]] SDL_DisplayOrientation orientation() const;
|
||||
|
||||
[[nodiscard]] bool grabKeyboard(bool enable);
|
||||
[[nodiscard]] bool grabMouse(bool enable);
|
||||
void setBordered(bool bordered);
|
||||
void raise();
|
||||
void resizeable(bool use);
|
||||
void fullscreen(bool enter, bool forceOriginalDisplay);
|
||||
void minimize();
|
||||
|
||||
[[nodiscard]] bool resize(const SDL_Point& size);
|
||||
|
||||
[[nodiscard]] bool drawRect(SDL_Surface* surface, SDL_Point offset, const SDL_Rect& srcRect);
|
||||
[[nodiscard]] bool drawRects(SDL_Surface* surface, SDL_Point offset,
|
||||
const std::vector<SDL_Rect>& rects = {});
|
||||
[[nodiscard]] bool drawScaledRect(SDL_Surface* surface, const SDL_FPoint& scale,
|
||||
const SDL_Rect& srcRect);
|
||||
|
||||
[[nodiscard]] bool drawScaledRects(SDL_Surface* surface, const SDL_FPoint& scale,
|
||||
const std::vector<SDL_Rect>& rects = {});
|
||||
|
||||
[[nodiscard]] bool fill(Uint8 r = 0x00, Uint8 g = 0x00, Uint8 b = 0x00, Uint8 a = 0xff);
|
||||
[[nodiscard]] bool blit(SDL_Surface* surface, const SDL_Rect& src, SDL_Rect& dst);
|
||||
void updateSurface();
|
||||
|
||||
protected:
|
||||
SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect, Uint32 flags);
|
||||
|
||||
[[nodiscard]] static bool fill(SDL_Window* window, Uint8 r = 0x00, Uint8 g = 0x00,
|
||||
Uint8 b = 0x00, Uint8 a = 0xff);
|
||||
[[nodiscard]] static rdpMonitor query(SDL_Window* window, SDL_DisplayID id,
|
||||
bool forceAsPrimary = false);
|
||||
[[nodiscard]] static SDL_Rect rect(SDL_Window* window, bool forceAsPrimary = false);
|
||||
[[nodiscard]] static SDL_Rect rect(SDL_DisplayID id, bool forceAsPrimary = false);
|
||||
|
||||
enum HighDPIMode
|
||||
{
|
||||
MODE_INVALID,
|
||||
MODE_NONE,
|
||||
MODE_WINDOWS,
|
||||
MODE_MACOS
|
||||
};
|
||||
|
||||
[[nodiscard]] static enum HighDPIMode isHighDPIWindowsMode(SDL_Window* window);
|
||||
|
||||
private:
|
||||
SDL_Window* _window = nullptr;
|
||||
SDL_DisplayID _displayID = 0;
|
||||
Sint32 _offset_x = 0;
|
||||
Sint32 _offset_y = 0;
|
||||
rdpMonitor _monitor{};
|
||||
};
|
||||
Reference in New Issue
Block a user