FreeRDP
Loading...
Searching...
No Matches
SDL3/sdl_window.cpp
1
20#include <limits>
21#include <sstream>
22
23#include "sdl_window.hpp"
24#include "sdl_utils.hpp"
25
26SdlWindow::SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect,
27 [[maybe_unused]] Uint32 flags)
28 : _displayID(id)
29{
30 auto props = SDL_CreateProperties();
31 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title.c_str());
32 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, rect.x);
33 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, rect.y);
34 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, rect.w);
35 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, rect.h);
36
37 if (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)
38 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
39
40 if (flags & SDL_WINDOW_FULLSCREEN)
41 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
42
43 if (flags & SDL_WINDOW_BORDERLESS)
44 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
45
46 _window = SDL_CreateWindowWithProperties(props);
47 SDL_DestroyProperties(props);
48
49 auto sc = scale();
50 const int iscale = static_cast<int>(sc * 100.0f);
51 auto w = 100 * rect.w / iscale;
52 auto h = 100 * rect.h / iscale;
53 std::ignore = resize({ w, h });
54 SDL_SetHint(SDL_HINT_APP_NAME, "");
55 std::ignore = SDL_SyncWindow(_window);
56}
57
58SdlWindow::SdlWindow(SdlWindow&& other) noexcept
59 : _window(other._window), _displayID(other._displayID), _offset_x(other._offset_x),
60 _offset_y(other._offset_y)
61{
62 other._window = nullptr;
63}
64
65SdlWindow::~SdlWindow()
66{
67 SDL_DestroyWindow(_window);
68}
69
70SDL_WindowID SdlWindow::id() const
71{
72 if (!_window)
73 return 0;
74 return SDL_GetWindowID(_window);
75}
76
77SDL_DisplayID SdlWindow::displayIndex() const
78{
79 if (!_window)
80 return 0;
81 return SDL_GetDisplayForWindow(_window);
82}
83
84SDL_Rect SdlWindow::rect() const
85{
86 SDL_Rect rect = {};
87 if (_window)
88 {
89 SDL_GetWindowPosition(_window, &rect.x, &rect.y);
90 SDL_GetWindowSizeInPixels(_window, &rect.w, &rect.h);
91 }
92 return rect;
93}
94
95SDL_Rect SdlWindow::bounds() const
96{
97 SDL_Rect rect = {};
98 if (_window)
99 {
100 SDL_GetWindowPosition(_window, &rect.x, &rect.y);
101 SDL_GetWindowSize(_window, &rect.w, &rect.h);
102 }
103 return rect;
104}
105
106SDL_Window* SdlWindow::window() const
107{
108 return _window;
109}
110
111Sint32 SdlWindow::offsetX() const
112{
113 return _offset_x;
114}
115
116void SdlWindow::setOffsetX(Sint32 x)
117{
118 _offset_x = x;
119}
120
121void SdlWindow::setOffsetY(Sint32 y)
122{
123 _offset_y = y;
124}
125
126Sint32 SdlWindow::offsetY() const
127{
128 return _offset_y;
129}
130
131rdpMonitor SdlWindow::monitor(bool isPrimary) const
132{
133 rdpMonitor mon{};
134
135 const auto factor = scale();
136 const auto dsf = static_cast<UINT32>(100 * factor);
137 mon.attributes.desktopScaleFactor = dsf;
138 mon.attributes.deviceScaleFactor = 100;
139
140 const auto r = rect();
141 mon.width = r.w;
142 mon.height = r.h;
143
144 mon.attributes.physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, r.w);
145 mon.attributes.physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, r.h);
146
147 SDL_Rect rect = {};
148 auto did = SDL_GetDisplayForWindow(_window);
149 auto rc = SDL_GetDisplayBounds(did, &rect);
150
151 if (rc)
152 {
153 mon.x = rect.x;
154 mon.y = rect.y;
155 }
156
157 const auto orient = orientation();
158 mon.attributes.orientation = sdl::utils::orientaion_to_rdp(orient);
159
160 auto primary = SDL_GetPrimaryDisplay();
161 mon.is_primary = isPrimary || (SDL_GetWindowID(_window) == primary);
162 mon.orig_screen = did;
163 if (mon.is_primary)
164 {
165 mon.x = 0;
166 mon.y = 0;
167 }
168 return mon;
169}
170
171float SdlWindow::scale() const
172{
173 return SDL_GetWindowDisplayScale(_window);
174}
175
176SDL_DisplayOrientation SdlWindow::orientation() const
177{
178 const auto did = displayIndex();
179 return SDL_GetCurrentDisplayOrientation(did);
180}
181
182bool SdlWindow::grabKeyboard(bool enable)
183{
184 if (!_window)
185 return false;
186 SDL_SetWindowKeyboardGrab(_window, enable);
187 return true;
188}
189
190bool SdlWindow::grabMouse(bool enable)
191{
192 if (!_window)
193 return false;
194 SDL_SetWindowMouseGrab(_window, enable);
195 return true;
196}
197
198void SdlWindow::setBordered(bool bordered)
199{
200 if (_window)
201 SDL_SetWindowBordered(_window, bordered);
202 std::ignore = SDL_SyncWindow(_window);
203}
204
205void SdlWindow::raise()
206{
207 SDL_RaiseWindow(_window);
208 std::ignore = SDL_SyncWindow(_window);
209}
210
211void SdlWindow::resizeable(bool use)
212{
213 SDL_SetWindowResizable(_window, use);
214 std::ignore = SDL_SyncWindow(_window);
215}
216
217void SdlWindow::fullscreen(bool enter, bool forceOriginalDisplay)
218{
219 if (enter && forceOriginalDisplay && _displayID != 0)
220 {
221 /* Move the window to the desired display. We should not wait
222 * for the window to be moved, because some backends can refuse
223 * the move. The intent of moving the window is enough for SDL
224 * to decide which display will be used for fullscreen. */
225 SDL_Rect rect = {};
226 std::ignore = SDL_GetDisplayBounds(_displayID, &rect);
227 std::ignore = SDL_SetWindowPosition(_window, rect.x, rect.y);
228 }
229 std::ignore = SDL_SetWindowFullscreen(_window, enter);
230 std::ignore = SDL_SyncWindow(_window);
231}
232
233void SdlWindow::minimize()
234{
235 SDL_MinimizeWindow(_window);
236 std::ignore = SDL_SyncWindow(_window);
237}
238
239bool SdlWindow::resize(const SDL_Point& size)
240{
241 return SDL_SetWindowSize(_window, size.x, size.y);
242}
243
244bool SdlWindow::drawRect(SDL_Surface* surface, SDL_Point offset, const SDL_Rect& srcRect)
245{
246 WINPR_ASSERT(surface);
247 SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
248 return blit(surface, srcRect, dstRect);
249}
250
251bool SdlWindow::drawRects(SDL_Surface* surface, SDL_Point offset,
252 const std::vector<SDL_Rect>& rects)
253{
254 if (rects.empty())
255 {
256 return drawRect(surface, offset, { 0, 0, surface->w, surface->h });
257 }
258 for (auto& srcRect : rects)
259 {
260 if (!drawRect(surface, offset, srcRect))
261 return false;
262 }
263 return true;
264}
265
266bool SdlWindow::drawScaledRect(SDL_Surface* surface, const SDL_FPoint& scale,
267 const SDL_Rect& srcRect)
268{
269 SDL_Rect dstRect = srcRect;
270 dstRect.x = static_cast<Sint32>(static_cast<float>(dstRect.x) * scale.x);
271 dstRect.w = static_cast<Sint32>(static_cast<float>(dstRect.w) * scale.x);
272 dstRect.y = static_cast<Sint32>(static_cast<float>(dstRect.y) * scale.y);
273 dstRect.h = static_cast<Sint32>(static_cast<float>(dstRect.h) * scale.y);
274 return blit(surface, srcRect, dstRect);
275}
276
277bool SdlWindow::drawScaledRects(SDL_Surface* surface, const SDL_FPoint& scale,
278 const std::vector<SDL_Rect>& rects)
279{
280 if (rects.empty())
281 {
282 return drawScaledRect(surface, scale, { 0, 0, surface->w, surface->h });
283 }
284 for (const auto& srcRect : rects)
285 {
286 if (!drawScaledRect(surface, scale, srcRect))
287 return false;
288 }
289 return true;
290}
291
292bool SdlWindow::fill(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
293{
294 auto surface = SDL_GetWindowSurface(_window);
295 if (!surface)
296 return false;
297 SDL_Rect rect = { 0, 0, surface->w, surface->h };
298 auto color = SDL_MapSurfaceRGBA(surface, r, g, b, a);
299
300 SDL_FillSurfaceRect(surface, &rect, color);
301 return true;
302}
303
304bool SdlWindow::blit(SDL_Surface* surface, const SDL_Rect& srcRect, SDL_Rect& dstRect)
305{
306 auto screen = SDL_GetWindowSurface(_window);
307 if (!screen || !surface)
308 return false;
309 if (!SDL_SetSurfaceClipRect(surface, &srcRect))
310 return true;
311 if (!SDL_SetSurfaceClipRect(screen, &dstRect))
312 return true;
313 if (!SDL_BlitSurfaceScaled(surface, &srcRect, screen, &dstRect, SDL_SCALEMODE_LINEAR))
314 {
315 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL_BlitScaled: %s", SDL_GetError());
316 return false;
317 }
318 return true;
319}
320
321void SdlWindow::updateSurface()
322{
323 SDL_UpdateWindowSurface(_window);
324}
325
326SdlWindow SdlWindow::create(SDL_DisplayID id, const std::string& title, Uint32 flags, Uint32 width,
327 Uint32 height)
328{
329 flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
330
331 SDL_Rect rect = { static_cast<int>(SDL_WINDOWPOS_CENTERED_DISPLAY(id)),
332 static_cast<int>(SDL_WINDOWPOS_CENTERED_DISPLAY(id)), static_cast<int>(width),
333 static_cast<int>(height) };
334
335 if ((flags & SDL_WINDOW_FULLSCREEN) != 0)
336 {
337 std::ignore = SDL_GetDisplayBounds(id, &rect);
338 }
339
340 SdlWindow window{ id, title, rect, flags };
341
342 if ((flags & (SDL_WINDOW_FULLSCREEN)) != 0)
343 {
344 window.setOffsetX(rect.x);
345 window.setOffsetY(rect.y);
346 }
347
348 return window;
349}
SdlWindow(const std::string &title, Sint32 startupX, Sint32 startupY, Sint32 width, Sint32 height, Uint32 flags)