22#include "sdl_connection_dialog.hpp"
23#include "../sdl_utils.hpp"
24#include "../sdl_context.hpp"
25#include "res/sdl3_resource_manager.hpp"
27static const SDL_Color textcolor = { 0xd1, 0xcf, 0xcd, 0xff };
28static const SDL_Color infocolor = { 0x43, 0xe0, 0x0f, 0x60 };
29static const SDL_Color warncolor = { 0xcd, 0xca, 0x35, 0x60 };
30static const SDL_Color errorcolor = { 0xf7, 0x22, 0x30, 0x60 };
32static const Uint32 vpadding = 5;
33static const Uint32 hpadding = 5;
35SDLConnectionDialog::SDLConnectionDialog(rdpContext* context) : _context(context)
42SDLConnectionDialog::~SDLConnectionDialog()
48bool SDLConnectionDialog::setTitle(
const char* fmt, ...)
50 std::scoped_lock lock(_mux);
53 _title = print(fmt, ap);
56 return show(SdlConnectionDialogWrapper::MSG_NONE);
59bool SDLConnectionDialog::showInfo(
const char* fmt, ...)
63 auto rc = show(SdlConnectionDialogWrapper::MSG_INFO, fmt, ap);
68bool SDLConnectionDialog::showWarn(
const char* fmt, ...)
72 auto rc = show(SdlConnectionDialogWrapper::MSG_WARN, fmt, ap);
77bool SDLConnectionDialog::showError(
const char* fmt, ...)
81 auto rc = show(SdlConnectionDialogWrapper::MSG_ERROR, fmt, ap);
88bool SDLConnectionDialog::show()
90 std::scoped_lock lock(_mux);
91 return show(_type_active);
94bool SDLConnectionDialog::hide()
96 std::scoped_lock lock(_mux);
97 return show(SdlConnectionDialogWrapper::MSG_DISCARD);
100bool SDLConnectionDialog::running()
const
102 std::scoped_lock lock(_mux);
106bool SDLConnectionDialog::updateMsg(SdlConnectionDialogWrapper::MsgType type)
110 case SdlConnectionDialogWrapper::MSG_INFO:
111 case SdlConnectionDialogWrapper::MSG_WARN:
112 case SdlConnectionDialogWrapper::MSG_ERROR:
117 case SdlConnectionDialogWrapper::MSG_DISCARD:
124 SDL_SetWindowTitle(_window.get(), _title.c_str());
131bool SDLConnectionDialog::setModal()
135 auto sdl = get_context(_context);
136 auto parent =
sdl->getFirstWindow();
140 if (!SDL_SetWindowParent(_window.get(), parent->window()))
142 if (!SDL_SetWindowModal(_window.get(),
true))
144 if (!SDL_RaiseWindow(_window.get()))
150bool SDLConnectionDialog::updateInternal()
152 std::scoped_lock lock(_mux);
153 for (
auto& btn : _list)
155 if (!btn.widget.update_text(_msg))
162bool SDLConnectionDialog::wait(
bool ignoreRdpContext)
166 if (!ignoreRdpContext)
168 if (freerdp_shall_disconnect_context(_context))
171 std::this_thread::yield();
176bool SDLConnectionDialog::handle(
const SDL_Event& event)
181 windowID = SDL_GetWindowID(_window.get());
186 case SDL_EVENT_USER_RETRY_DIALOG:
188 std::scoped_lock lock(_mux);
189 auto type =
static_cast<SdlConnectionDialogWrapper::MsgType
>(
event.user.code);
190 return updateMsg(type);
196 case SDL_EVENT_KEY_DOWN:
197 case SDL_EVENT_KEY_UP:
200 auto& ev =
reinterpret_cast<const SDL_KeyboardEvent&
>(event);
203 switch (event.key.key)
209 if (event.type == SDL_EVENT_KEY_UP)
211 freerdp_abort_connect_context(_context);
212 std::ignore = sdl_push_quit();
216 if (!_buttons.set_highlight_next())
223 return windowID == ev.windowID;
226 case SDL_EVENT_MOUSE_MOTION:
229 auto& ev =
reinterpret_cast<const SDL_MouseMotionEvent&
>(event);
231 _buttons.set_mouseover(event.button.x, event.button.y);
234 return windowID == ev.windowID;
237 case SDL_EVENT_MOUSE_BUTTON_DOWN:
238 case SDL_EVENT_MOUSE_BUTTON_UP:
241 auto& ev =
reinterpret_cast<const SDL_MouseButtonEvent&
>(event);
245 auto button = _buttons.get_selected(event.button);
248 if (event.type == SDL_EVENT_MOUSE_BUTTON_UP)
250 freerdp_abort_connect_context(_context);
251 std::ignore = sdl_push_quit();
255 return windowID == ev.windowID;
258 case SDL_EVENT_MOUSE_WHEEL:
261 auto& ev =
reinterpret_cast<const SDL_MouseWheelEvent&
>(event);
264 return windowID == ev.windowID;
267 case SDL_EVENT_FINGER_UP:
268 case SDL_EVENT_FINGER_DOWN:
271 auto& ev =
reinterpret_cast<const SDL_TouchFingerEvent&
>(event);
274 return windowID == ev.windowID;
278 if ((event.type >= SDL_EVENT_WINDOW_FIRST) && (
event.type <= SDL_EVENT_WINDOW_LAST))
280 auto& ev =
reinterpret_cast<const SDL_WindowEvent&
>(event);
283 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
284 if (windowID == ev.windowID)
286 freerdp_abort_connect_context(_context);
287 std::ignore = sdl_push_quit();
298 return windowID == ev.windowID;
304bool SDLConnectionDialog::visible()
const
306 std::scoped_lock lock(_mux);
307 return SdlWidgetList::visible();
310bool SDLConnectionDialog::createWindow()
314 const size_t widget_height = 50;
315 const size_t widget_width = 600;
316 const size_t total_height = 300;
318 if (!reset(_title, widget_width, total_height))
324 SDL_Color res_bgcolor;
325 switch (_type_active)
327 case SdlConnectionDialogWrapper::MSG_INFO:
328 res_bgcolor = infocolor;
330 case SdlConnectionDialogWrapper::MSG_WARN:
331 res_bgcolor = warncolor;
333 case SdlConnectionDialogWrapper::MSG_ERROR:
334 res_bgcolor = errorcolor;
336 case SdlConnectionDialogWrapper::MSG_DISCARD:
338 res_bgcolor = _backgroundcolor;
342#if defined(WITH_SDL_IMAGE_DIALOGS)
343 std::string res_name;
344 switch (_type_active)
346 case SdlConnectionDialogWrapper::MSG_INFO:
347 res_name =
"icon_info.svg";
349 case SdlConnectionDialogWrapper::MSG_WARN:
350 res_name =
"icon_warning.svg";
352 case SdlConnectionDialogWrapper::MSG_ERROR:
353 res_name =
"icon_error.svg";
355 case SdlConnectionDialogWrapper::MSG_DISCARD:
361 const auto height = (total_height - 3.0f * vpadding) / 2.0f;
362 SDL_FRect iconRect{ hpadding, vpadding, widget_width / 4.0f - 2.0f * hpadding, height };
363 widget_cfg_t icon{ textcolor,
365 { _renderer, iconRect,
367 _list.emplace_back(std::move(icon));
369 iconRect.y += height;
371 widget_cfg_t logo{ textcolor,
373 { _renderer, iconRect,
375 "FreeRDP_Icon.svg") } };
376 _list.emplace_back(std::move(logo));
378 SDL_FRect rect = { widget_width / 4.0f, vpadding, widget_width * 3.0f / 4.0f,
379 total_height - 3ul * vpadding - widget_height };
381 SDL_FRect rect = { hpadding, vpadding, widget_width - 2ul * hpadding,
382 total_height - 2ul * vpadding };
385 widget_cfg_t w{ textcolor, _backgroundcolor, { _renderer, rect } };
386 if (!w.widget.set_wrap(
true, widget_width))
388 _list.emplace_back(std::move(w));
389 rect.y += widget_height + vpadding;
391 const std::vector<int> buttonids = { 1 };
392 const std::vector<std::string> buttonlabels = {
"cancel" };
393 if (!_buttons.populate(_renderer, buttonlabels, buttonids, widget_width,
394 total_height - widget_height - vpadding,
395 static_cast<Sint32
>(widget_width / 2),
396 static_cast<Sint32
>(widget_height)))
398 if (!_buttons.set_highlight(0))
401 if (!SDL_ShowWindow(_window.get()))
403 if (!SDL_RaiseWindow(_window.get()))
409void SDLConnectionDialog::destroyWindow()
417bool SDLConnectionDialog::show(SdlConnectionDialogWrapper::MsgType type,
const char* fmt,
420 std::scoped_lock lock(_mux);
421 _msg = print(fmt, ap);
425bool SDLConnectionDialog::show(SdlConnectionDialogWrapper::MsgType type)
427 if (SDL_IsMainThread())
428 return updateMsg(type);
430 return sdl_push_user_event(SDL_EVENT_USER_RETRY_DIALOG, type);
433std::string SDLConnectionDialog::print(
const char* fmt, va_list ap)
442 res.resize(WINPR_ASSERTING_INT_CAST(uint32_t, size));
446 WINPR_PRAGMA_DIAG_PUSH
447 WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
448 size = vsnprintf(res.data(), res.size(), fmt, copy);
449 WINPR_PRAGMA_DIAG_POP
452 }
while ((size > 0) && (
static_cast<size_t>(size) > res.size()));
457bool SDLConnectionDialog::setTimer(Uint32 timeoutMS)
459 std::scoped_lock lock(_mux);
462 _timer = SDL_AddTimer(timeoutMS, &SDLConnectionDialog::timeout,
this);
467void SDLConnectionDialog::resetTimer()
470 SDL_RemoveTimer(_timer);
474Uint32 SDLConnectionDialog::timeout(
void* pvthis, [[maybe_unused]] SDL_TimerID timerID,
475 [[maybe_unused]] Uint32 intervalMS)
478 std::ignore = self->hide();
479 self->_running =
false;
static SDL_IOStream * get(const std::string &type, const std::string &id)