24#include "sdl_window.hpp"
25#include "sdl_utils.hpp"
27#include <freerdp/utils/string.h>
30 [[maybe_unused]] Uint32 flags)
33 auto props = SDL_CreateProperties();
34 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title.c_str());
35 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, rect.x);
36 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, rect.y);
37 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, rect.w);
38 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, rect.h);
40 if (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)
41 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN,
true);
43 if (flags & SDL_WINDOW_FULLSCREEN)
44 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN,
true);
46 if (flags & SDL_WINDOW_BORDERLESS)
47 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN,
true);
49 _window = SDL_CreateWindowWithProperties(props);
50 SDL_DestroyProperties(props);
53 const int iscale =
static_cast<int>(sc * 100.0f);
54 auto w = 100 * rect.w / iscale;
55 auto h = 100 * rect.h / iscale;
56 std::ignore = resize({ w, h });
57 SDL_SetHint(SDL_HINT_APP_NAME,
"");
58 std::ignore = SDL_SyncWindow(_window);
60 _monitor = query(_window,
id,
true);
64 : _window(other._window), _displayID(other._displayID), _offset_x(other._offset_x),
65 _offset_y(other._offset_y), _monitor(other._monitor)
67 other._window =
nullptr;
70SdlWindow::~SdlWindow()
72 SDL_DestroyWindow(_window);
75SDL_WindowID SdlWindow::id()
const
79 return SDL_GetWindowID(_window);
82SDL_DisplayID SdlWindow::displayIndex()
const
86 return SDL_GetDisplayForWindow(_window);
89SDL_Rect SdlWindow::rect()
const
94SDL_Rect SdlWindow::bounds()
const
99 if (!SDL_GetWindowPosition(_window, &rect.x, &rect.y))
101 if (!SDL_GetWindowSize(_window, &rect.w, &rect.h))
107SDL_Window* SdlWindow::window()
const
112Sint32 SdlWindow::offsetX()
const
117void SdlWindow::setOffsetX(Sint32 x)
122void SdlWindow::setOffsetY(Sint32 y)
127Sint32 SdlWindow::offsetY()
const
132rdpMonitor SdlWindow::monitor(
bool isPrimary)
const
148float SdlWindow::scale()
const
150 return SDL_GetWindowDisplayScale(_window);
153SDL_DisplayOrientation SdlWindow::orientation()
const
155 const auto did = displayIndex();
156 return SDL_GetCurrentDisplayOrientation(did);
159bool SdlWindow::grabKeyboard(
bool enable)
163 SDL_SetWindowKeyboardGrab(_window, enable);
167bool SdlWindow::grabMouse(
bool enable)
171 SDL_SetWindowMouseGrab(_window, enable);
175void SdlWindow::setBordered(
bool bordered)
178 SDL_SetWindowBordered(_window, bordered);
179 std::ignore = SDL_SyncWindow(_window);
182void SdlWindow::raise()
184 SDL_RaiseWindow(_window);
185 std::ignore = SDL_SyncWindow(_window);
188void SdlWindow::resizeable(
bool use)
190 SDL_SetWindowResizable(_window, use);
191 std::ignore = SDL_SyncWindow(_window);
194void SdlWindow::fullscreen(
bool enter,
bool forceOriginalDisplay)
196 if (enter && forceOriginalDisplay && _displayID != 0)
203 std::ignore = SDL_GetDisplayBounds(_displayID, &rect);
204 std::ignore = SDL_SetWindowPosition(_window, rect.x, rect.y);
206 std::ignore = SDL_SetWindowFullscreen(_window, enter);
207 std::ignore = SDL_SyncWindow(_window);
210void SdlWindow::minimize()
212 SDL_MinimizeWindow(_window);
213 std::ignore = SDL_SyncWindow(_window);
216bool SdlWindow::resize(
const SDL_Point& size)
218 return SDL_SetWindowSize(_window, size.x, size.y);
221bool SdlWindow::drawRect(SDL_Surface* surface, SDL_Point offset,
const SDL_Rect& srcRect)
223 WINPR_ASSERT(surface);
224 SDL_Rect dstRect = { offset.x + srcRect.x, offset.y + srcRect.y, srcRect.w, srcRect.h };
225 return blit(surface, srcRect, dstRect);
228bool SdlWindow::drawRects(SDL_Surface* surface, SDL_Point offset,
229 const std::vector<SDL_Rect>& rects)
233 return drawRect(surface, offset, { 0, 0, surface->w, surface->h });
235 for (
auto& srcRect : rects)
237 if (!drawRect(surface, offset, srcRect))
243bool SdlWindow::drawScaledRect(SDL_Surface* surface,
const SDL_FPoint& scale,
244 const SDL_Rect& srcRect)
246 SDL_Rect dstRect = srcRect;
247 dstRect.x =
static_cast<Sint32
>(
static_cast<float>(dstRect.x) * scale.x);
248 dstRect.w =
static_cast<Sint32
>(
static_cast<float>(dstRect.w) * scale.x);
249 dstRect.y =
static_cast<Sint32
>(
static_cast<float>(dstRect.y) * scale.y);
250 dstRect.h =
static_cast<Sint32
>(
static_cast<float>(dstRect.h) * scale.y);
251 return blit(surface, srcRect, dstRect);
254bool SdlWindow::drawScaledRects(SDL_Surface* surface,
const SDL_FPoint& scale,
255 const std::vector<SDL_Rect>& rects)
259 return drawScaledRect(surface, scale, { 0, 0, surface->w, surface->h });
261 for (
const auto& srcRect : rects)
263 if (!drawScaledRect(surface, scale, srcRect))
269bool SdlWindow::fill(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
271 return fill(_window, r, g, b, a);
274bool SdlWindow::fill(SDL_Window* window, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
276 auto surface = SDL_GetWindowSurface(window);
279 SDL_Rect rect = { 0, 0, surface->w, surface->h };
280 auto color = SDL_MapSurfaceRGBA(surface, r, g, b, a);
282 return SDL_FillSurfaceRect(surface, &rect, color);
285rdpMonitor SdlWindow::query(SDL_Window* window, SDL_DisplayID
id,
bool forceAsPrimary)
290 const auto& r = rect(window, forceAsPrimary);
291 const float factor = SDL_GetWindowDisplayScale(window);
292 const float dpi = std::roundf(factor * 100.0f);
294 WINPR_ASSERT(r.w > 0);
295 WINPR_ASSERT(r.h > 0);
297 const auto primary = SDL_GetPrimaryDisplay();
298 const auto orientation = SDL_GetCurrentDisplayOrientation(
id);
299 const auto rdp_orientation = sdl::utils::orientaion_to_rdp(orientation);
302 monitor.orig_screen = id;
306 monitor.height = r.h;
307 monitor.is_primary = forceAsPrimary || (
id == primary);
308 monitor.attributes.desktopScaleFactor =
static_cast<UINT32
>(dpi);
309 monitor.attributes.deviceScaleFactor = 100;
310 monitor.attributes.orientation = rdp_orientation;
311 monitor.attributes.physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, r.w);
312 monitor.attributes.physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, r.h);
314 const auto cat = SDL_LOG_CATEGORY_APPLICATION;
315 SDL_LogDebug(cat,
"monitor.orig_screen %" PRIu32, monitor.orig_screen);
316 SDL_LogDebug(cat,
"monitor.x %" PRId32, monitor.x);
317 SDL_LogDebug(cat,
"monitor.y %" PRId32, monitor.y);
318 SDL_LogDebug(cat,
"monitor.width %" PRId32, monitor.width);
319 SDL_LogDebug(cat,
"monitor.height %" PRId32, monitor.height);
320 SDL_LogDebug(cat,
"monitor.is_primary %" PRIu32, monitor.is_primary);
321 SDL_LogDebug(cat,
"monitor.attributes.desktopScaleFactor %" PRIu32,
322 monitor.attributes.desktopScaleFactor);
323 SDL_LogDebug(cat,
"monitor.attributes.deviceScaleFactor %" PRIu32,
324 monitor.attributes.deviceScaleFactor);
325 SDL_LogDebug(cat,
"monitor.attributes.orientation %s",
326 freerdp_desktop_rotation_flags_to_string(monitor.attributes.orientation));
327 SDL_LogDebug(cat,
"monitor.attributes.physicalWidth %" PRIu32,
328 monitor.attributes.physicalWidth);
329 SDL_LogDebug(cat,
"monitor.attributes.physicalHeight %" PRIu32,
330 monitor.attributes.physicalHeight);
334SDL_Rect SdlWindow::rect(SDL_Window* window,
bool forceAsPrimary)
342 if (!SDL_GetWindowPosition(window, &rect.x, &rect.y))
346 if (!SDL_GetWindowSizeInPixels(window, &rect.w, &rect.h))
352SdlWindow::HighDPIMode SdlWindow::isHighDPIWindowsMode(SDL_Window* window)
357 const auto id = SDL_GetDisplayForWindow(window);
361 const auto cs = SDL_GetDisplayContentScale(
id);
362 const auto ds = SDL_GetWindowDisplayScale(window);
363 const auto pd = SDL_GetWindowPixelDensity(window);
366 if ((cs == 1.0f) && (ds == 1.0f) && (pd == 1.0f))
370 if ((cs == 1.0f) && (ds > 1.0f) && (pd > 1.0f))
377bool SdlWindow::blit(SDL_Surface* surface,
const SDL_Rect& srcRect, SDL_Rect& dstRect)
379 auto screen = SDL_GetWindowSurface(_window);
380 if (!screen || !surface)
382 if (!SDL_SetSurfaceClipRect(surface, &srcRect))
384 if (!SDL_SetSurfaceClipRect(screen, &dstRect))
386 if (!SDL_BlitSurfaceScaled(surface, &srcRect, screen, &dstRect, SDL_SCALEMODE_LINEAR))
388 SDL_LogError(SDL_LOG_CATEGORY_RENDER,
"SDL_BlitScaled: %s", SDL_GetError());
394void SdlWindow::updateSurface()
396 SDL_UpdateWindowSurface(_window);
399SdlWindow SdlWindow::create(SDL_DisplayID
id,
const std::string& title, Uint32 flags, Uint32 width,
402 flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
404 SDL_Rect rect = {
static_cast<int>(SDL_WINDOWPOS_CENTERED_DISPLAY(
id)),
405 static_cast<int>(SDL_WINDOWPOS_CENTERED_DISPLAY(
id)),
static_cast<int>(width),
406 static_cast<int>(height) };
408 if ((flags & SDL_WINDOW_FULLSCREEN) != 0)
410 std::ignore = SDL_GetDisplayBounds(
id, &rect);
413 SdlWindow window{ id, title, rect, flags };
415 if ((flags & (SDL_WINDOW_FULLSCREEN)) != 0)
417 window.setOffsetX(rect.x);
418 window.setOffsetY(rect.y);
424static SDL_Window* createDummy(SDL_DisplayID
id)
426 const auto x = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
427 const auto y = SDL_WINDOWPOS_CENTERED_DISPLAY(
id);
431 auto props = SDL_CreateProperties();
432 std::stringstream ss;
433 ss <<
"SdlWindow::query(" <<
id <<
")";
434 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, ss.str().c_str());
435 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x);
436 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y);
437 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w);
438 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h);
440 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN,
true);
441 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN,
true);
442 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN,
true);
443 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN,
false);
445 auto window = SDL_CreateWindowWithProperties(props);
446 SDL_DestroyProperties(props);
450rdpMonitor SdlWindow::query(SDL_DisplayID
id,
bool forceAsPrimary)
452 std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> window(createDummy(
id), SDL_DestroyWindow);
456 std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> renderer(
457 SDL_CreateRenderer(window.get(),
nullptr), SDL_DestroyRenderer);
459 if (!SDL_SyncWindow(window.get()))
463 while (SDL_PollEvent(&event))
466 return query(window.get(),
id, forceAsPrimary);
469SDL_Rect SdlWindow::rect(SDL_DisplayID
id,
bool forceAsPrimary)
471 std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> window(createDummy(
id), SDL_DestroyWindow);
475 std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> renderer(
476 SDL_CreateRenderer(window.get(),
nullptr), SDL_DestroyRenderer);
478 if (!SDL_SyncWindow(window.get()))
482 while (SDL_PollEvent(&event))
485 return rect(window.get(), forceAsPrimary);
SdlWindow(const std::string &title, Sint32 startupX, Sint32 startupY, Sint32 width, Sint32 height, Uint32 flags)