Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View 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;
};