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 = 200; 
 
   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 =
 
  122    layout.PhysicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, _targetWidth);
 
  123    layout.PhysicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, _targetHeight);
 
  125    if (IFCALLRESULT(CHANNEL_RC_OK, _disp->SendMonitorLayout, _disp, 1, &layout) !=
 
  129  return update_last_sent();
 
  132BOOL 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;
 
  157void 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)
 
  179void 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();
 
  198Uint32 sdlDispContext::OnTimer(Uint32 interval, 
void* param)
 
  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");
 
  233UINT 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 = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
 
  255    layout->Height = WINPR_ASSERTING_INT_CAST(uint32_t, 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),
 
  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#if defined(WITH_DEBUG_SDL_EVENTS) 
  343  SDL_Log(
"got windowEvent %s [0x%08" PRIx32 
"]", sdl_window_event_str(ev->event).c_str(),
 
  350  auto it = _sdl->windows.find(ev->windowID);
 
  351  if (it != _sdl->windows.end())
 
  352    it->second.setBordered(bordered);
 
  356    case SDL_WINDOWEVENT_HIDDEN:
 
  357    case SDL_WINDOWEVENT_MINIMIZED:
 
  358      gdi_send_suppress_output(_sdl->context()->gdi, TRUE);
 
  361    case SDL_WINDOWEVENT_EXPOSED:
 
  362    case SDL_WINDOWEVENT_SHOWN:
 
  363    case SDL_WINDOWEVENT_MAXIMIZED:
 
  364    case SDL_WINDOWEVENT_RESTORED:
 
  365      gdi_send_suppress_output(_sdl->context()->gdi, FALSE);
 
  368    case SDL_WINDOWEVENT_RESIZED:
 
  369    case SDL_WINDOWEVENT_SIZE_CHANGED:
 
  370      _targetWidth = ev->data1;
 
  371      _targetHeight = ev->data2;
 
  374    case SDL_WINDOWEVENT_LEAVE:
 
  376      _sdl->input.keyboard_grab(ev->windowID, 
false);
 
  378    case SDL_WINDOWEVENT_ENTER:
 
  380      _sdl->input.keyboard_grab(ev->windowID, 
true);
 
  381      return _sdl->input.keyboard_focus_in();
 
  382    case SDL_WINDOWEVENT_FOCUS_GAINED:
 
  383    case SDL_WINDOWEVENT_TAKE_FOCUS:
 
  384      return _sdl->input.keyboard_focus_in();
 
  391UINT sdlDispContext::DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
 
  392                                        UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
 
  398  return sdlDisp->DisplayControlCaps(maxNumMonitors, maxMonitorAreaFactorA,
 
  399                                     maxMonitorAreaFactorB);
 
  402UINT sdlDispContext::DisplayControlCaps(UINT32 maxNumMonitors, UINT32 maxMonitorAreaFactorA,
 
  403                                        UINT32 maxMonitorAreaFactorB)
 
  405  auto settings = _sdl->context()->settings;
 
  406  WINPR_ASSERT(settings);
 
  409           "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 
" MaxMonitorAreaFactorA: %" PRIu32
 
  410           " MaxMonitorAreaFactorB: %" PRIu32 
"",
 
  411           maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
 
  415    return CHANNEL_RC_OK;
 
  417  WLog_DBG(TAG, 
"DisplayControlCapsPdu: setting the window as resizable");
 
  418  return set_window_resizable() ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
 
  421BOOL sdlDispContext::init(DispClientContext* disp)
 
  426  auto settings = _sdl->context()->settings;
 
  436    disp->DisplayControlCaps = sdlDispContext::DisplayControlCaps;
 
  439  _sdl->update_resizeable(TRUE);
 
  443BOOL sdlDispContext::uninit(DispClientContext* disp)
 
  449  _sdl->update_resizeable(FALSE);
 
  453sdlDispContext::sdlDispContext(
SdlContext* sdl) : _sdl(sdl)
 
  455  SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
 
  458  WINPR_ASSERT(_sdl->context()->settings);
 
  459  WINPR_ASSERT(_sdl->context()->pubSub);
 
  461  auto settings = _sdl->context()->settings;
 
  462  auto pubSub = _sdl->context()->pubSub;
 
  464  _lastSentWidth = _targetWidth =
 
  466  _lastSentHeight = _targetHeight =
 
  468  PubSub_SubscribeActivated(pubSub, sdlDispContext::OnActivated);
 
  469  PubSub_SubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset);
 
  473sdlDispContext::~sdlDispContext()
 
  475  wPubSub* pubSub = _sdl->context()->pubSub;
 
  476  WINPR_ASSERT(pubSub);
 
  478  PubSub_UnsubscribeActivated(pubSub, sdlDispContext::OnActivated);
 
  479  PubSub_UnsubscribeGraphicsReset(pubSub, sdlDispContext::OnGraphicsReset);
 
  480  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 UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.