21#include <winpr/sysinfo.h>
22#include <winpr/assert.h>
24#include <freerdp/gdi/gdi.h>
28#include "sdl_disp.hpp"
30#include "sdl_utils.hpp"
31#include "sdl_freerdp.hpp"
33#include <freerdp/log.h>
34#define TAG CLIENT_TAG("sdl.disp")
36static constexpr UINT64 RESIZE_MIN_DELAY = 500;
37static constexpr unsigned MAX_RETRIES = 5;
39BOOL sdlDispContext::settings_changed()
41 auto settings = _sdl->context()->settings;
42 WINPR_ASSERT(settings);
44 if (_lastSentWidth != _targetWidth)
47 if (_lastSentHeight != _targetHeight)
50 if (_lastSentDesktopOrientation !=
54 if (_lastSentDesktopScaleFactor !=
58 if (_lastSentDeviceScaleFactor !=
68BOOL sdlDispContext::update_last_sent()
72 auto settings = _sdl->context()->settings;
73 WINPR_ASSERT(settings);
75 _lastSentWidth = _targetWidth;
76 _lastSentHeight = _targetHeight;
84BOOL sdlDispContext::sendResize()
87 auto settings = _sdl->context()->settings;
92 if (!_activated || !_disp)
95 if (GetTickCount64() - _lastSentDate < RESIZE_MIN_DELAY)
98 _lastSentDate = GetTickCount64();
100 if (!settings_changed())
104 if (_sdl->fullscreen && (mcount > 0))
106 auto monitors =
static_cast<const rdpMonitor*
>(
108 if (sendLayout(monitors, mcount) != CHANNEL_RC_OK)
113 _waitingResize = TRUE;
114 layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
115 layout.Top = layout.Left = 0;
116 layout.Width = WINPR_ASSERTING_INT_CAST(uint32_t, _targetWidth);
117 layout.Height = WINPR_ASSERTING_INT_CAST(uint32_t, _targetHeight);
119 layout.DesktopScaleFactor =
123 layout.PhysicalWidth = 0;
124 layout.PhysicalHeight = 0;
126 if (IFCALLRESULT(CHANNEL_RC_OK, _disp->SendMonitorLayout, _disp, 1, &layout) !=
130 return update_last_sent();
133BOOL sdlDispContext::set_window_resizable()
135 _sdl->update_resizeable(TRUE);
140 rdpSettings** ppSettings)
145 auto sdl = get_context(context);
149 if (!
sdl->context()->settings)
153 *ppsdlDisp = &
sdl->disp;
154 *ppSettings =
sdl->context()->settings;
158void sdlDispContext::OnActivated(
void* context,
const ActivatedEventArgs* e)
162 rdpSettings* settings =
nullptr;
164 if (!sdl_disp_check_context(context, &
sdl, &sdlDisp, &settings))
167 sdlDisp->_waitingResize = FALSE;
171 sdlDisp->set_window_resizable();
173 if (e->firstActivation)
180void sdlDispContext::OnGraphicsReset(
void* context,
const GraphicsResetEventArgs* e)
184 rdpSettings* settings =
nullptr;
187 if (!sdl_disp_check_context(context, &
sdl, &sdlDisp, &settings))
190 sdlDisp->_waitingResize = FALSE;
194 sdlDisp->set_window_resizable();
199Uint32 sdlDispContext::OnTimer(Uint32 interval,
void* param)
210 rdpSettings* settings =
nullptr;
212 if (!sdl_disp_check_context(
sdl->context(), &
sdl, &sdlDisp, &settings))
215 WLog_Print(
sdl->log, WLOG_TRACE,
"checking for display changes...");
220 auto rc = sdlDisp->sendResize();
222 WLog_Print(
sdl->log, WLOG_TRACE,
"sent new display layout, result %d", rc);
224 if (sdlDisp->_timer_retries++ >= MAX_RETRIES)
226 WLog_Print(
sdl->log, WLOG_TRACE,
"deactivate timer, retries exceeded");
230 WLog_Print(
sdl->log, WLOG_TRACE,
"fire timer one more time");
234UINT sdlDispContext::sendLayout(
const rdpMonitor* monitors,
size_t nmonitors)
236 UINT ret = CHANNEL_RC_OK;
238 WINPR_ASSERT(monitors);
239 WINPR_ASSERT(nmonitors > 0);
241 auto settings = _sdl->context()->settings;
242 WINPR_ASSERT(settings);
244 std::vector<DISPLAY_CONTROL_MONITOR_LAYOUT> layouts;
245 layouts.resize(nmonitors);
247 for (
size_t i = 0; i < nmonitors; i++)
249 auto monitor = &monitors[i];
250 auto& layout = layouts.at(i);
252 layout.Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
253 layout.Left = monitor->x;
254 layout.Top = monitor->y;
255 layout.Width = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
256 layout.Height = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
257 layout.Orientation = ORIENTATION_LANDSCAPE;
258 layout.PhysicalWidth = monitor->attributes.physicalWidth;
259 layout.PhysicalHeight = monitor->attributes.physicalHeight;
261 switch (monitor->attributes.orientation)
264 layout.Orientation = ORIENTATION_PORTRAIT;
268 layout.Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
272 layout.Orientation = ORIENTATION_PORTRAIT_FLIPPED;
284 layout.Orientation = ORIENTATION_LANDSCAPE;
288 layout.DesktopScaleFactor =
294 const size_t len = layouts.size();
295 WINPR_ASSERT(len <= UINT32_MAX);
296 ret = IFCALLRESULT(CHANNEL_RC_OK, _disp->SendMonitorLayout, _disp,
static_cast<UINT32
>(len),
301BOOL sdlDispContext::addTimer()
303 if (SDL_WasInit(SDL_INIT_TIMER) == 0)
306 SDL_RemoveTimer(_timer);
307 WLog_Print(_sdl->log, WLOG_TRACE,
"adding new display check timer");
311 _timer = SDL_AddTimer(1000, sdlDispContext::OnTimer,
this);
315#if SDL_VERSION_ATLEAST(2, 0, 10)
316BOOL sdlDispContext::handle_display_event(
const SDL_DisplayEvent* ev)
322#if SDL_VERSION_ATLEAST(2, 0, 14)
323 case SDL_DISPLAYEVENT_CONNECTED:
324 SDL_Log(
"A new display with id %u was connected", ev->display);
326 case SDL_DISPLAYEVENT_DISCONNECTED:
327 SDL_Log(
"The display with id %u was disconnected", ev->display);
330 case SDL_DISPLAYEVENT_ORIENTATION:
331 SDL_Log(
"The orientation of display with id %u was changed", ev->display);
339BOOL sdlDispContext::handle_window_event(
const SDL_WindowEvent* ev)
342 WLog_Print(_sdl->log, WLOG_TRACE,
"got windowEvent %s [0x%08" PRIx32
"]",
343 sdl_window_event_str(ev->event).c_str(), ev->event);
348 auto it = _sdl->windows.find(ev->windowID);
349 if (it != _sdl->windows.end())
350 it->second.setBordered(bordered);
354 case SDL_WINDOWEVENT_HIDDEN:
355 case SDL_WINDOWEVENT_MINIMIZED:
356 return gdi_send_suppress_output(_sdl->context()->gdi, TRUE);
358 case SDL_WINDOWEVENT_EXPOSED:
359 case SDL_WINDOWEVENT_SHOWN:
360 case SDL_WINDOWEVENT_MAXIMIZED:
361 case SDL_WINDOWEVENT_RESTORED:
362 return gdi_send_suppress_output(_sdl->context()->gdi, FALSE);
364 case SDL_WINDOWEVENT_RESIZED:
365 case SDL_WINDOWEVENT_SIZE_CHANGED:
366 _targetWidth = ev->data1;
367 _targetHeight = ev->data2;
370 case SDL_WINDOWEVENT_LEAVE:
372 _sdl->input.keyboard_grab(ev->windowID,
false);
374 case SDL_WINDOWEVENT_ENTER:
376 _sdl->input.keyboard_grab(ev->windowID,
true);
377 return _sdl->input.keyboard_focus_in();
378 case SDL_WINDOWEVENT_FOCUS_GAINED:
379 case SDL_WINDOWEVENT_TAKE_FOCUS:
380 return _sdl->input.keyboard_focus_in();
387UINT sdlDispContext::DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
388 UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
394 return sdlDisp->DisplayControlCaps(maxNumMonitors, maxMonitorAreaFactorA,
395 maxMonitorAreaFactorB);
398UINT sdlDispContext::DisplayControlCaps(UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA,
399 UINT32 maxMonitorAreaFactorB)
401 auto settings = _sdl->context()->settings;
402 WINPR_ASSERT(settings);
405 "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32
" MaxMonitorAreaFactorA: %" PRIu32
406 " MaxMonitorAreaFactorB: %" PRIu32
"",
407 maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
411 return CHANNEL_RC_OK;
413 WLog_DBG(TAG,
"DisplayControlCapsPdu: setting the window as resizable");
414 return set_window_resizable() ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
417BOOL sdlDispContext::init(DispClientContext* disp)
422 auto settings = _sdl->context()->settings;
432 disp->DisplayControlCaps = sdlDispContext::DisplayControlCaps;
435 _sdl->update_resizeable(TRUE);
439BOOL sdlDispContext::uninit(DispClientContext* disp)
445 _sdl->update_resizeable(FALSE);
451 SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
454 WINPR_ASSERT(_sdl->context()->settings);
455 WINPR_ASSERT(_sdl->context()->pubSub);
457 auto settings = _sdl->context()->settings;
458 auto pubSub = _sdl->context()->pubSub;
460 _lastSentWidth = _targetWidth =
462 _lastSentHeight = _targetHeight =
464 if (PubSub_SubscribeActivated(pubSub, sdlDispContext::OnActivated) < 0)
465 throw std::exception();
466 if (PubSub_SubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset) < 0)
467 throw std::exception();
471sdlDispContext::~sdlDispContext()
473 wPubSub* pubSub = _sdl->context()->pubSub;
474 WINPR_ASSERT(pubSub);
476 PubSub_UnsubscribeActivated(pubSub, sdlDispContext::OnActivated);
477 PubSub_UnsubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset);
478 SDL_RemoveTimer(_timer);
WINPR_ATTR_NODISCARD FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.