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_freerdp.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
40static 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 return FALSE;
65 }
66
67 return TRUE;
68}
69
70static void sdl_Pointer_Clear(sdlPointer* ptr)
71{
72 WINPR_ASSERT(ptr);
73 SDL_DestroyCursor(ptr->cursor);
74 SDL_DestroySurface(ptr->image);
75 ptr->cursor = nullptr;
76 ptr->image = nullptr;
77}
78
79static void sdl_Pointer_Free(rdpContext* context, rdpPointer* pointer)
80{
81 auto ptr = reinterpret_cast<sdlPointer*>(pointer);
82 WINPR_UNUSED(context);
83
84 if (ptr)
85 {
86 sdl_Pointer_Clear(ptr);
87 winpr_aligned_free(ptr->data);
88 ptr->data = nullptr;
89 }
90}
91
92static BOOL sdl_Pointer_SetDefault(rdpContext* context)
93{
94 WINPR_UNUSED(context);
95
96 return sdl_push_user_event(SDL_EVENT_USER_POINTER_DEFAULT);
97}
98
99static BOOL sdl_Pointer_Set(rdpContext* context, rdpPointer* pointer)
100{
101 WINPR_UNUSED(context);
102 return sdl_push_user_event(SDL_EVENT_USER_POINTER_SET, pointer);
103}
104
105BOOL sdl_Pointer_Set_Process(SdlContext* sdl)
106{
107 INT32 w = 0;
108 INT32 h = 0;
109
110 WINPR_ASSERT(sdl);
111
112 auto context = sdl->context();
113 auto pointer = sdl->cursor();
114 auto ptr = reinterpret_cast<sdlPointer*>(pointer);
115 if (!ptr)
116 return TRUE;
117
118 rdpGdi* gdi = context->gdi;
119 WINPR_ASSERT(gdi);
120
121 auto x = static_cast<INT32>(pointer->xPos);
122 auto y = static_cast<INT32>(pointer->yPos);
123 auto sw = w = static_cast<INT32>(pointer->width);
124 auto sh = h = static_cast<INT32>(pointer->height);
125
126 SDL_Window* window = SDL_GetMouseFocus();
127 if (!window)
128 return sdl_Pointer_SetDefault(context);
129
130 const Uint32 id = SDL_GetWindowID(window);
131
132 if (!sdl_scale_coordinates(sdl, id, &x, &y, FALSE, FALSE) ||
133 !sdl_scale_coordinates(sdl, id, &sw, &sh, FALSE, FALSE))
134 return FALSE;
135
136 sdl_Pointer_Clear(ptr);
137
138 ptr->image = SDL_CreateSurface(sw, sh, sdl->sdl_pixel_format);
139 if (!ptr->image)
140 return FALSE;
141
142 SDL_LockSurface(ptr->image);
143 auto pixels = static_cast<BYTE*>(ptr->image->pixels);
144 auto data = static_cast<const BYTE*>(ptr->data);
145 const BOOL rc = freerdp_image_scale(
146 pixels, gdi->dstFormat, static_cast<UINT32>(ptr->image->pitch), 0, 0,
147 static_cast<UINT32>(ptr->image->w), static_cast<UINT32>(ptr->image->h), data,
148 gdi->dstFormat, 0, 0, 0, static_cast<UINT32>(w), static_cast<UINT32>(h));
149 SDL_UnlockSurface(ptr->image);
150 if (!rc)
151 return FALSE;
152
153 // create a cursor image in 100% display scale to trick SDL into creating the cursor with the
154 // correct size
155 auto it = sdl->windows.begin();
156 if (it == sdl->windows.end())
157 return FALSE;
158
159 const auto hidpi_scale = SDL_GetWindowDisplayScale(it->second.window());
160 auto normal = SDL_CreateSurface(
161 static_cast<int>(static_cast<float>(ptr->image->w) / hidpi_scale),
162 static_cast<int>(static_cast<float>(ptr->image->h) / hidpi_scale), ptr->image->format);
163 assert(normal);
164 SDL_BlitSurfaceScaled(ptr->image, nullptr, normal, nullptr,
165 SDL_ScaleMode::SDL_SCALEMODE_LINEAR);
166 SDL_AddSurfaceAlternateImage(normal, ptr->image);
167
168 ptr->cursor = SDL_CreateColorCursor(normal, x, y);
169 if (!ptr->cursor)
170 return FALSE;
171
172 SDL_DestroySurface(normal);
173
174 SDL_SetCursor(ptr->cursor);
175 SDL_ShowCursor();
176 sdl->setHasCursor(true);
177 return TRUE;
178}
179
180static BOOL sdl_Pointer_SetNull(rdpContext* context)
181{
182 WINPR_UNUSED(context);
183
184 return sdl_push_user_event(SDL_EVENT_USER_POINTER_NULL);
185}
186
187static BOOL sdl_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y)
188{
189 WINPR_UNUSED(context);
190 WINPR_ASSERT(context);
191
192 return sdl_push_user_event(SDL_EVENT_USER_POINTER_POSITION, x, y);
193}
194
195BOOL sdl_register_pointer(rdpGraphics* graphics)
196{
197 const rdpPointer pointer = { sizeof(sdlPointer),
198 sdl_Pointer_New,
199 sdl_Pointer_Free,
200 sdl_Pointer_Set,
201 sdl_Pointer_SetNull,
202 sdl_Pointer_SetDefault,
203 sdl_Pointer_SetPosition,
204 {},
205 0,
206 0,
207 0,
208 0,
209 0,
210 0,
211 0,
212 nullptr,
213 nullptr,
214 {} };
215 graphics_register_pointer(graphics, &pointer);
216 return TRUE;
217}