FreeRDP
Loading...
Searching...
No Matches
SDL3/sdl_pointer.cpp
1
20#include <freerdp/config.h>
21
22#include <freerdp/gdi/gdi.h>
23
24#include "sdl_pointer.hpp"
25#include "sdl_context.hpp"
26#include "sdl_touch.hpp"
27#include "sdl_utils.hpp"
28
29#include <SDL3/SDL_mouse.h>
30
31typedef struct
32{
33 rdpPointer pointer;
34 SDL_Cursor* cursor;
35 SDL_Surface* image;
36 size_t size;
37 void* data;
38} sdlPointer;
39
40[[nodiscard]] static BOOL sdl_Pointer_New(rdpContext* context, rdpPointer* pointer)
41{
42 auto ptr = reinterpret_cast<sdlPointer*>(pointer);
43
44 WINPR_ASSERT(context);
45 if (!ptr)
46 return FALSE;
47
48 rdpGdi* gdi = context->gdi;
49 WINPR_ASSERT(gdi);
50
51 ptr->size = 4ull * pointer->width * pointer->height;
52 ptr->data = winpr_aligned_malloc(ptr->size, 16);
53
54 if (!ptr->data)
55 return FALSE;
56
57 auto data = static_cast<BYTE*>(ptr->data);
58 if (!freerdp_image_copy_from_pointer_data(
59 data, gdi->dstFormat, 0, 0, 0, pointer->width, pointer->height, pointer->xorMaskData,
60 pointer->lengthXorMask, pointer->andMaskData, pointer->lengthAndMask, pointer->xorBpp,
61 &context->gdi->palette))
62 {
63 winpr_aligned_free(ptr->data);
64 ptr->data = nullptr;
65 return FALSE;
66 }
67
68 return TRUE;
69}
70
71static void sdl_Pointer_Clear(sdlPointer* ptr)
72{
73 WINPR_ASSERT(ptr);
74 SDL_DestroyCursor(ptr->cursor);
75 SDL_DestroySurface(ptr->image);
76 ptr->cursor = nullptr;
77 ptr->image = nullptr;
78}
79
80static void sdl_Pointer_Free(rdpContext* context, rdpPointer* pointer)
81{
82 auto ptr = reinterpret_cast<sdlPointer*>(pointer);
83 WINPR_UNUSED(context);
84
85 if (ptr)
86 {
87 sdl_Pointer_Clear(ptr);
88 winpr_aligned_free(ptr->data);
89 ptr->data = nullptr;
90 }
91}
92
93[[nodiscard]] static BOOL sdl_Pointer_SetDefault(rdpContext* context)
94{
95 WINPR_UNUSED(context);
96
97 return sdl_push_user_event(SDL_EVENT_USER_POINTER_DEFAULT);
98}
99
100[[nodiscard]] static BOOL sdl_Pointer_Set(rdpContext* context, rdpPointer* pointer)
101{
102 WINPR_UNUSED(context);
103 return sdl_push_user_event(SDL_EVENT_USER_POINTER_SET, pointer);
104}
105
106bool sdl_Pointer_Set_Process(SdlContext* sdl)
107{
108 WINPR_ASSERT(sdl);
109
110 auto context = sdl->context();
111 auto pointer = sdl->cursor();
112 auto ptr = reinterpret_cast<sdlPointer*>(pointer);
113 if (!ptr)
114 return true;
115
116 rdpGdi* gdi = context->gdi;
117 WINPR_ASSERT(gdi);
118
119 auto ix = static_cast<float>(pointer->xPos);
120 auto iy = static_cast<float>(pointer->yPos);
121 auto isw = static_cast<float>(pointer->width);
122 auto ish = static_cast<float>(pointer->height);
123
124 auto window = SDL_GetMouseFocus();
125 if (!window)
126 return sdl_Pointer_SetDefault(context);
127
128 const Uint32 id = SDL_GetWindowID(window);
129
130 const SDL_FRect orig{ ix, iy, isw, ish };
131 auto pos = sdl->pixelToScreen(id, orig);
132 WLog_Print(sdl->getWLog(), WLOG_DEBUG, "cursor scale: pixel:%s, display:%s",
133 sdl::utils::toString(orig).c_str(), sdl::utils::toString(pos).c_str());
134
135 sdl_Pointer_Clear(ptr);
136
137 ptr->image =
138 SDL_CreateSurface(static_cast<int>(orig.w), static_cast<int>(orig.h), sdl->pixelFormat());
139 if (!ptr->image)
140 {
141 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_CreateSurface failed");
142 return false;
143 }
144
145 if (!SDL_LockSurface(ptr->image))
146 {
147 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_LockSurface failed");
148 return false;
149 }
150
151 auto pixels = static_cast<BYTE*>(ptr->image->pixels);
152 auto data = static_cast<const BYTE*>(ptr->data);
153 const BOOL rc = freerdp_image_scale(
154 pixels, gdi->dstFormat, static_cast<UINT32>(ptr->image->pitch), 0, 0,
155 static_cast<UINT32>(ptr->image->w), static_cast<UINT32>(ptr->image->h), data,
156 gdi->dstFormat, 0, 0, 0, static_cast<UINT32>(isw), static_cast<UINT32>(ish));
157 SDL_UnlockSurface(ptr->image);
158 if (!rc)
159 {
160 WLog_Print(sdl->getWLog(), WLOG_ERROR, "freerdp_image_scale failed");
161 return false;
162 }
163
164 // create a cursor image in 100% display scale to trick SDL into creating the cursor with the
165 // correct size
166 auto fw = sdl->getFirstWindow();
167 if (!fw)
168 {
169 WLog_Print(sdl->getWLog(), WLOG_ERROR, "sdl->getFirstWindow() nullptr");
170 return false;
171 }
172
173 const auto hidpi_scale =
174 sdl->pixelToScreen(fw->id(), SDL_FPoint{ static_cast<float>(ptr->image->w),
175 static_cast<float>(ptr->image->h) });
176 std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)> normal{
177 SDL_CreateSurface(static_cast<int>(hidpi_scale.x), static_cast<int>(hidpi_scale.y),
178 ptr->image->format),
179 SDL_DestroySurface
180 };
181 assert(normal);
182 if (!SDL_BlitSurfaceScaled(ptr->image, nullptr, normal.get(), nullptr,
183 SDL_ScaleMode::SDL_SCALEMODE_LINEAR))
184 {
185 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_BlitSurfaceScaled failed");
186 return false;
187 }
188 if (!SDL_AddSurfaceAlternateImage(normal.get(), ptr->image))
189 {
190 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_AddSurfaceAlternateImage failed");
191 return false;
192 }
193
194 ptr->cursor =
195 SDL_CreateColorCursor(normal.get(), static_cast<int>(pos.x), static_cast<int>(pos.y));
196 if (!ptr->cursor)
197 {
198 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_CreateColorCursor(display:%s, pixel:%s} failed",
199 sdl::utils::toString(pos).c_str(), sdl::utils::toString(orig).c_str());
200 return false;
201 }
202
203 if (!SDL_SetCursor(ptr->cursor))
204 {
205 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_SetCursor failed");
206 return false;
207 }
208 if (!SDL_ShowCursor())
209 {
210 WLog_Print(sdl->getWLog(), WLOG_ERROR, "SDL_ShowCursor failed");
211 return false;
212 }
213 sdl->setHasCursor(true);
214 return true;
215}
216
217[[nodiscard]] static BOOL sdl_Pointer_SetNull(rdpContext* context)
218{
219 WINPR_UNUSED(context);
220
221 return sdl_push_user_event(SDL_EVENT_USER_POINTER_NULL);
222}
223
224[[nodiscard]] static BOOL sdl_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
225{
226 WINPR_UNUSED(context);
227 WINPR_ASSERT(context);
228
229 return sdl_push_user_event(SDL_EVENT_USER_POINTER_POSITION, x, y);
230}
231
232bool sdl_register_pointer(rdpGraphics* graphics)
233{
234 const rdpPointer pointer = { sizeof(sdlPointer),
235 sdl_Pointer_New,
236 sdl_Pointer_Free,
237 sdl_Pointer_Set,
238 sdl_Pointer_SetNull,
239 sdl_Pointer_SetDefault,
240 sdl_Pointer_SetPosition,
241 {},
242 0,
243 0,
244 0,
245 0,
246 0,
247 0,
248 0,
249 nullptr,
250 nullptr,
251 {} };
252 graphics_register_pointer(graphics, &pointer);
253 return true;
254}