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)
40SDLConnectionDialog::~SDLConnectionDialog()
46bool SDLConnectionDialog::setTitle(
const char* fmt, ...)
48 std::scoped_lock lock(_mux);
51 _title = print(fmt, ap);
54 return show(SdlConnectionDialogWrapper::MSG_NONE);
57bool SDLConnectionDialog::showInfo(
const char* fmt, ...)
61 auto rc = show(SdlConnectionDialogWrapper::MSG_INFO, fmt, ap);
66bool SDLConnectionDialog::showWarn(
const char* fmt, ...)
70 auto rc = show(SdlConnectionDialogWrapper::MSG_WARN, fmt, ap);
75bool SDLConnectionDialog::showError(
const char* fmt, ...)
79 auto rc = show(SdlConnectionDialogWrapper::MSG_ERROR, fmt, ap);
86bool SDLConnectionDialog::show()
88 std::scoped_lock lock(_mux);
89 return show(_type_active);
92bool SDLConnectionDialog::hide()
94 std::scoped_lock lock(_mux);
95 return show(SdlConnectionDialogWrapper::MSG_DISCARD);
98bool SDLConnectionDialog::running()
const
100 std::scoped_lock lock(_mux);
104bool SDLConnectionDialog::updateMsg(SdlConnectionDialogWrapper::MsgType type)
108 case SdlConnectionDialogWrapper::MSG_INFO:
109 case SdlConnectionDialogWrapper::MSG_WARN:
110 case SdlConnectionDialogWrapper::MSG_ERROR:
115 case SdlConnectionDialogWrapper::MSG_DISCARD:
122 SDL_SetWindowTitle(_window.get(), _title.c_str());
129bool SDLConnectionDialog::setModal()
133 auto sdl = get_context(_context);
134 auto parent = sdl->getFirstWindow();
138 if (!SDL_SetWindowParent(_window.get(), parent->window()))
140 if (!SDL_SetWindowModal(_window.get(),
true))
142 if (!SDL_RaiseWindow(_window.get()))
148bool SDLConnectionDialog::updateInternal()
150 std::scoped_lock lock(_mux);
151 for (
auto& btn : _list)
153 if (!btn.widget.update_text(_msg))
160bool SDLConnectionDialog::wait(
bool ignoreRdpContext)
164 if (!ignoreRdpContext)
166 if (freerdp_shall_disconnect_context(_context))
169 std::this_thread::yield();
174bool SDLConnectionDialog::handle(
const SDL_Event& event)
179 windowID = SDL_GetWindowID(_window.get());
184 case SDL_EVENT_USER_RETRY_DIALOG:
186 std::scoped_lock lock(_mux);
187 auto type =
static_cast<SdlConnectionDialogWrapper::MsgType
>(
event.user.code);
188 return updateMsg(type);
194 case SDL_EVENT_KEY_DOWN:
195 case SDL_EVENT_KEY_UP:
198 auto& ev =
reinterpret_cast<const SDL_KeyboardEvent&
>(event);
201 switch (event.key.key)
207 if (event.type == SDL_EVENT_KEY_UP)
209 freerdp_abort_event(_context);
210 std::ignore = sdl_push_quit();
214 if (!_buttons.set_highlight_next())
221 return windowID == ev.windowID;
224 case SDL_EVENT_MOUSE_MOTION:
227 auto& ev =
reinterpret_cast<const SDL_MouseMotionEvent&
>(event);
229 _buttons.set_mouseover(event.button.x, event.button.y);
232 return windowID == ev.windowID;
235 case SDL_EVENT_MOUSE_BUTTON_DOWN:
236 case SDL_EVENT_MOUSE_BUTTON_UP:
239 auto& ev =
reinterpret_cast<const SDL_MouseButtonEvent&
>(event);
243 auto button = _buttons.get_selected(event.button);
246 if (event.type == SDL_EVENT_MOUSE_BUTTON_UP)
248 freerdp_abort_event(_context);
249 std::ignore = sdl_push_quit();
253 return windowID == ev.windowID;
256 case SDL_EVENT_MOUSE_WHEEL:
259 auto& ev =
reinterpret_cast<const SDL_MouseWheelEvent&
>(event);
262 return windowID == ev.windowID;
265 case SDL_EVENT_FINGER_UP:
266 case SDL_EVENT_FINGER_DOWN:
269 auto& ev =
reinterpret_cast<const SDL_TouchFingerEvent&
>(event);
272 return windowID == ev.windowID;
276 if ((event.type >= SDL_EVENT_WINDOW_FIRST) && (
event.type <= SDL_EVENT_WINDOW_LAST))
278 auto& ev =
reinterpret_cast<const SDL_WindowEvent&
>(event);
281 case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
282 if (windowID == ev.windowID)
284 freerdp_abort_event(_context);
285 std::ignore = sdl_push_quit();
296 return windowID == ev.windowID;
302bool SDLConnectionDialog::visible()
const
304 std::scoped_lock lock(_mux);
305 return SdlWidgetList::visible();
308bool SDLConnectionDialog::createWindow()
312 const size_t widget_height = 50;
313 const size_t widget_width = 600;
314 const size_t total_height = 300;
316 if (!reset(_title, widget_width, total_height))
322 SDL_Color res_bgcolor;
323 switch (_type_active)
325 case SdlConnectionDialogWrapper::MSG_INFO:
326 res_bgcolor = infocolor;
328 case SdlConnectionDialogWrapper::MSG_WARN:
329 res_bgcolor = warncolor;
331 case SdlConnectionDialogWrapper::MSG_ERROR:
332 res_bgcolor = errorcolor;
334 case SdlConnectionDialogWrapper::MSG_DISCARD:
336 res_bgcolor = _backgroundcolor;
340#if defined(WITH_SDL_IMAGE_DIALOGS)
341 std::string res_name;
342 switch (_type_active)
344 case SdlConnectionDialogWrapper::MSG_INFO:
345 res_name =
"icon_info.svg";
347 case SdlConnectionDialogWrapper::MSG_WARN:
348 res_name =
"icon_warning.svg";
350 case SdlConnectionDialogWrapper::MSG_ERROR:
351 res_name =
"icon_error.svg";
353 case SdlConnectionDialogWrapper::MSG_DISCARD:
359 const auto height = (total_height - 3.0f * vpadding) / 2.0f;
360 SDL_FRect iconRect{ hpadding, vpadding, widget_width / 4.0f - 2.0f * hpadding, height };
361 widget_cfg_t icon{ textcolor,
363 { _renderer, iconRect,
365 _list.emplace_back(std::move(icon));
367 iconRect.y += height;
369 widget_cfg_t logo{ textcolor,
371 { _renderer, iconRect,
373 "FreeRDP_Icon.svg") } };
374 _list.emplace_back(std::move(logo));
376 SDL_FRect rect = { widget_width / 4.0f, vpadding, widget_width * 3.0f / 4.0f,
377 total_height - 3ul * vpadding - widget_height };
379 SDL_FRect rect = { hpadding, vpadding, widget_width - 2ul * hpadding,
380 total_height - 2ul * vpadding };
383 widget_cfg_t w{ textcolor, _backgroundcolor, { _renderer, rect } };
384 if (!w.widget.set_wrap(
true, widget_width))
386 _list.emplace_back(std::move(w));
387 rect.y += widget_height + vpadding;
389 const std::vector<int> buttonids = { 1 };
390 const std::vector<std::string> buttonlabels = {
"cancel" };
391 if (!_buttons.populate(_renderer, buttonlabels, buttonids, widget_width,
392 total_height - widget_height - vpadding,
393 static_cast<Sint32
>(widget_width / 2),
394 static_cast<Sint32
>(widget_height)))
396 if (!_buttons.set_highlight(0))
399 if (!SDL_ShowWindow(_window.get()))
401 if (!SDL_RaiseWindow(_window.get()))
407void SDLConnectionDialog::destroyWindow()
415bool SDLConnectionDialog::show(SdlConnectionDialogWrapper::MsgType type,
const char* fmt,
418 std::scoped_lock lock(_mux);
419 _msg = print(fmt, ap);
423bool SDLConnectionDialog::show(SdlConnectionDialogWrapper::MsgType type)
425 if (SDL_IsMainThread())
426 return updateMsg(type);
428 return sdl_push_user_event(SDL_EVENT_USER_RETRY_DIALOG, type);
431std::string SDLConnectionDialog::print(
const char* fmt, va_list ap)
440 res.resize(WINPR_ASSERTING_INT_CAST(uint32_t, size));
444 WINPR_PRAGMA_DIAG_PUSH
445 WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
446 size = vsnprintf(res.data(), res.size(), fmt, copy);
447 WINPR_PRAGMA_DIAG_POP
450 }
while ((size > 0) && (
static_cast<size_t>(size) > res.size()));
455bool SDLConnectionDialog::setTimer(Uint32 timeoutMS)
457 std::scoped_lock lock(_mux);
460 _timer = SDL_AddTimer(timeoutMS, &SDLConnectionDialog::timeout,
this);
465void SDLConnectionDialog::resetTimer()
468 SDL_RemoveTimer(_timer);
472Uint32 SDLConnectionDialog::timeout(
void* pvthis, [[maybe_unused]] SDL_TimerID timerID,
473 [[maybe_unused]] Uint32 intervalMS)
476 std::ignore = self->hide();
477 self->_running =
false;
static SDL_IOStream * get(const std::string &type, const std::string &id)