21 #include <winpr/sysinfo.h>
22 #include <winpr/assert.h>
24 #include <freerdp/gdi/gdi.h>
28 #include "sdl_disp.hpp"
29 #include "sdl_kbd.hpp"
30 #include "sdl_utils.hpp"
31 #include "sdl_freerdp.hpp"
33 #include <freerdp/log.h>
34 #define TAG CLIENT_TAG("sdl.disp")
36 static constexpr UINT64 RESIZE_MIN_DELAY = 200;
37 static constexpr
unsigned MAX_RETRIES = 5;
39 BOOL 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 !=
68 BOOL sdlDispContext::update_last_sent()
72 auto settings = _sdl->context()->settings;
73 WINPR_ASSERT(settings);
75 _lastSentWidth = _targetWidth;
76 _lastSentHeight = _targetHeight;
84 BOOL 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 = _targetWidth;
117 layout.Height = _targetHeight;
119 layout.DesktopScaleFactor =
122 layout.PhysicalWidth = _targetWidth;
123 layout.PhysicalHeight = _targetHeight;
125 if (IFCALLRESULT(CHANNEL_RC_OK, _disp->SendMonitorLayout, _disp, 1, &layout) !=
129 return update_last_sent();
132 BOOL sdlDispContext::set_window_resizable()
134 _sdl->update_resizeable(TRUE);
139 rdpSettings** ppSettings)
144 auto sdl = get_context(context);
148 if (!sdl->context()->settings)
152 *ppsdlDisp = &sdl->disp;
153 *ppSettings = sdl->context()->settings;
157 void sdlDispContext::OnActivated(
void* context,
const ActivatedEventArgs* e)
161 rdpSettings* settings =
nullptr;
163 if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
166 sdlDisp->_waitingResize = FALSE;
170 sdlDisp->set_window_resizable();
172 if (e->firstActivation)
179 void sdlDispContext::OnGraphicsReset(
void* context,
const GraphicsResetEventArgs* e)
183 rdpSettings* settings =
nullptr;
186 if (!sdl_disp_check_context(context, &sdl, &sdlDisp, &settings))
189 sdlDisp->_waitingResize = FALSE;
193 sdlDisp->set_window_resizable();
198 Uint32 sdlDispContext::OnTimer(
void* param, SDL_TimerID timerID, Uint32 interval)
209 rdpSettings* settings =
nullptr;
211 if (!sdl_disp_check_context(sdl->context(), &sdl, &sdlDisp, &settings))
214 WLog_Print(sdl->log, WLOG_TRACE,
"checking for display changes...");
219 auto rc = sdlDisp->sendResize();
221 WLog_Print(sdl->log, WLOG_TRACE,
"sent new display layout, result %d", rc);
223 if (sdlDisp->_timer_retries++ >= MAX_RETRIES)
225 WLog_Print(sdl->log, WLOG_TRACE,
"deactivate timer, retries exceeded");
229 WLog_Print(sdl->log, WLOG_TRACE,
"fire timer one more time");
233 UINT sdlDispContext::sendLayout(
const rdpMonitor* monitors,
size_t nmonitors)
235 UINT ret = CHANNEL_RC_OK;
237 WINPR_ASSERT(monitors);
238 WINPR_ASSERT(nmonitors > 0);
240 auto settings = _sdl->context()->settings;
241 WINPR_ASSERT(settings);
243 std::vector<DISPLAY_CONTROL_MONITOR_LAYOUT> layouts;
244 layouts.resize(nmonitors);
246 for (
size_t i = 0; i < nmonitors; i++)
248 auto monitor = &monitors[i];
249 auto layout = &layouts[i];
251 layout->Flags = (monitor->is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
252 layout->Left = monitor->x;
253 layout->Top = monitor->y;
254 layout->Width = monitor->width;
255 layout->Height = monitor->height;
256 layout->Orientation = ORIENTATION_LANDSCAPE;
257 layout->PhysicalWidth = monitor->attributes.physicalWidth;
258 layout->PhysicalHeight = monitor->attributes.physicalHeight;
260 switch (monitor->attributes.orientation)
263 layout->Orientation = ORIENTATION_PORTRAIT;
267 layout->Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
271 layout->Orientation = ORIENTATION_PORTRAIT_FLIPPED;
283 layout->Orientation = ORIENTATION_LANDSCAPE;
287 layout->DesktopScaleFactor =
289 layout->DeviceScaleFactor =
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),
301 BOOL sdlDispContext::addTimer()
303 if (SDL_WasInit(SDL_INIT_EVENTS) == 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 BOOL sdlDispContext::handle_display_event(
const SDL_DisplayEvent* ev)
321 case SDL_EVENT_DISPLAY_ADDED:
322 SDL_Log(
"A new display with id %u was connected", ev->displayID);
324 case SDL_EVENT_DISPLAY_REMOVED:
325 SDL_Log(
"The display with id %u was disconnected", ev->displayID);
327 case SDL_EVENT_DISPLAY_ORIENTATION:
328 SDL_Log(
"The orientation of display with id %u was changed", ev->displayID);
335 BOOL sdlDispContext::handle_window_event(
const SDL_WindowEvent* ev)
341 auto it = _sdl->windows.find(ev->windowID);
342 if (it != _sdl->windows.end())
343 it->second.setBordered(bordered);
347 case SDL_EVENT_WINDOW_HIDDEN:
348 case SDL_EVENT_WINDOW_MINIMIZED:
349 gdi_send_suppress_output(_sdl->context()->gdi, TRUE);
353 case SDL_EVENT_WINDOW_EXPOSED:
354 case SDL_EVENT_WINDOW_SHOWN:
355 case SDL_EVENT_WINDOW_MAXIMIZED:
356 case SDL_EVENT_WINDOW_RESTORED:
357 gdi_send_suppress_output(_sdl->context()->gdi, FALSE);
360 case SDL_EVENT_WINDOW_RESIZED:
361 case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
362 _targetWidth = ev->data1;
363 _targetHeight = ev->data2;
366 case SDL_EVENT_WINDOW_MOUSE_LEAVE:
368 _sdl->input.keyboard_grab(ev->windowID,
false);
370 case SDL_EVENT_WINDOW_MOUSE_ENTER:
372 _sdl->input.keyboard_grab(ev->windowID,
true);
373 return _sdl->input.keyboard_focus_in();
374 case SDL_EVENT_WINDOW_FOCUS_GAINED:
375 return _sdl->input.keyboard_focus_in();
382 UINT sdlDispContext::DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
383 UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
389 return sdlDisp->DisplayControlCaps(maxNumMonitors, maxMonitorAreaFactorA,
390 maxMonitorAreaFactorB);
393 UINT sdlDispContext::DisplayControlCaps(UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA,
394 UINT32 maxMonitorAreaFactorB)
396 auto settings = _sdl->context()->settings;
397 WINPR_ASSERT(settings);
400 "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32
" MaxMonitorAreaFactorA: %" PRIu32
401 " MaxMonitorAreaFactorB: %" PRIu32
"",
402 maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
406 return CHANNEL_RC_OK;
408 WLog_DBG(TAG,
"DisplayControlCapsPdu: setting the window as resizable");
409 return set_window_resizable() ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
412 BOOL sdlDispContext::init(DispClientContext* disp)
417 auto settings = _sdl->context()->settings;
427 disp->DisplayControlCaps = sdlDispContext::DisplayControlCaps;
430 _sdl->update_resizeable(TRUE);
434 BOOL sdlDispContext::uninit(DispClientContext* disp)
440 _sdl->update_resizeable(FALSE);
444 sdlDispContext::sdlDispContext(
SdlContext* sdl) : _sdl(sdl)
446 SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO);
449 WINPR_ASSERT(_sdl->context()->settings);
450 WINPR_ASSERT(_sdl->context()->pubSub);
452 auto settings = _sdl->context()->settings;
453 auto pubSub = _sdl->context()->pubSub;
457 PubSub_SubscribeActivated(pubSub, sdlDispContext::OnActivated);
458 PubSub_SubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset);
462 sdlDispContext::~sdlDispContext()
464 wPubSub* pubSub = _sdl->context()->pubSub;
465 WINPR_ASSERT(pubSub);
467 PubSub_UnsubscribeActivated(pubSub, sdlDispContext::OnActivated);
468 PubSub_UnsubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset);
469 SDL_RemoveTimer(_timer);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.