Skip to content

Commit

Permalink
[client,sdl] add connection dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
Armin Novak authored and akallabeth committed Dec 20, 2023
1 parent 49936fc commit e1de32f
Show file tree
Hide file tree
Showing 11 changed files with 572 additions and 16 deletions.
2 changes: 2 additions & 0 deletions client/SDL/dialogs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ set(SRCS
sdl_select.cpp
sdl_selectlist.hpp
sdl_selectlist.cpp
sdl_connection_dialog.cpp
sdl_connection_dialog.hpp
)

set(LIBS
Expand Down
363 changes: 363 additions & 0 deletions client/SDL/dialogs/sdl_connection_dialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,363 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SDL Client helper dialogs
*
* Copyright 2023 Armin Novak <armin.novak@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <thread>

#include "sdl_connection_dialog.hpp"
#include "../sdl_utils.hpp"
#include "../sdl_freerdp.hpp"

static const SDL_Color backgroundcolor = { 0x38, 0x36, 0x35, 0xff };
static const SDL_Color textcolor = { 0xd1, 0xcf, 0xcd, 0xff };

static const Uint32 hpadding = 10;
static const Uint32 vpadding = 5;

SDLConnectionDialog::SDLConnectionDialog(rdpContext* context)
: _context(context), _window(nullptr), _renderer(nullptr)
{
hide();
}

SDLConnectionDialog::~SDLConnectionDialog()
{
resetTimer();
destroyWindow();
}

bool SDLConnectionDialog::visible() const
{
return _window && _renderer;
}

bool SDLConnectionDialog::setTitle(const char* fmt, ...)
{
std::lock_guard lock(_mux);
va_list ap;
va_start(ap, fmt);
_title = print(fmt, ap);
va_end(ap);

return show(MSG_NONE);
}

bool SDLConnectionDialog::showInfo(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto rc = show(MSG_INFO, fmt, ap);
va_end(ap);
return rc;
}

bool SDLConnectionDialog::showWarn(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto rc = show(MSG_WARN, fmt, ap);
va_end(ap);
return rc;
}

bool SDLConnectionDialog::showError(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
auto rc = show(MSG_ERROR, fmt, ap);
va_end(ap);
return setTimer();
}

bool SDLConnectionDialog::hide()
{
std::lock_guard lock(_mux);
return show(MSG_DISCARD);
}

bool SDLConnectionDialog::running() const
{
std::lock_guard lock(_mux);
return _running;
}

bool SDLConnectionDialog::update()
{
std::lock_guard lock(_mux);
switch (_type)
{
case MSG_INFO:
case MSG_WARN:
case MSG_ERROR:
createWindow();
break;
case MSG_DISCARD:
resetTimer();
destroyWindow();
break;
default:
if (_window)
{
SDL_SetWindowTitle(_window, _title.c_str());
}
break;
}
_type = MSG_NONE;
return true;
}

bool SDLConnectionDialog::setModal()
{
if (_window)
{
auto sdl = get_context(_context);
if (sdl->windows.empty())
return true;

auto parent = sdl->windows.front().window;
SDL_SetWindowModalFor(_window, parent);
SDL_RaiseWindow(_window);
}
return true;
}

bool SDLConnectionDialog::clearWindow(SDL_Renderer* renderer)
{
assert(renderer);

const int drc = SDL_SetRenderDrawColor(renderer, backgroundcolor.r, backgroundcolor.g,
backgroundcolor.b, backgroundcolor.a);
if (widget_log_error(drc, "SDL_SetRenderDrawColor"))
return false;

const int rcls = SDL_RenderClear(renderer);
return !widget_log_error(rcls, "SDL_RenderClear");
}

bool SDLConnectionDialog::update(SDL_Renderer* renderer)
{
if (!renderer)
return false;

if (!clearWindow(renderer))
return false;

for (auto& btn : _list)
{
if (!btn.update_text(renderer, _msg, textcolor))
return false;
}

if (!_buttons.update(renderer))
return false;

SDL_RenderPresent(renderer);
return true;
}

bool SDLConnectionDialog::wait(bool ignoreRdpContext)
{
while (running())
{
if (!ignoreRdpContext)
{
if (freerdp_shall_disconnect_context(_context))
return false;
}
std::this_thread::yield();
}
return true;
}

bool SDLConnectionDialog::handle(const SDL_Event& event)
{
Uint32 windowID = 0;
if (_window)
{
windowID = SDL_GetWindowID(_window);
}

switch (event.type)
{
case SDL_USEREVENT_RETRY_DIALOG:
return update();
case SDL_QUIT:
resetTimer();
destroyWindow();
return false;
case SDL_KEYDOWN:
case SDL_KEYUP:
{
auto ev = reinterpret_cast<const SDL_KeyboardEvent&>(event);
update(_renderer);
return windowID == ev.windowID;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
auto ev = reinterpret_cast<const SDL_MouseButtonEvent&>(event);
update(_renderer);
return windowID == ev.windowID;
}
break;
case SDL_MOUSEWHEEL:
{
auto ev = reinterpret_cast<const SDL_MouseWheelEvent&>(event);
update(_renderer);
return windowID == ev.windowID;
}
break;
case SDL_FINGERUP:
case SDL_FINGERDOWN:
{
auto ev = reinterpret_cast<const SDL_TouchFingerEvent&>(event);
update(_renderer);
return windowID == ev.windowID;
}
case SDL_WINDOWEVENT:
{
auto ev = reinterpret_cast<const SDL_WindowEvent&>(event);
switch (ev.event)
{
case SDL_WINDOWEVENT_CLOSE:
if (windowID == ev.windowID)
{
resetTimer();
destroyWindow();
}
break;
default:
update(_renderer);
setModal();
break;
}

return windowID == ev.windowID;
}
default:
return false;
}
}

bool SDLConnectionDialog::createWindow()
{
destroyWindow();

const size_t widget_height = 50;
const size_t widget_width = 600;
const size_t total_height = 400;

_window = SDL_CreateWindow(_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
widget_width, total_height, 0);
if (_window == nullptr)
{
widget_log_error(-1, "SDL_CreateWindow");
return false;
}
setModal();

_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
if (_renderer == nullptr)
{
widget_log_error(-1, "SDL_CreateRenderer");
return false;
}

SDL_Rect rect = { 0, 0, widget_width, widget_height };
_list.push_back(SdlWidget(_renderer, rect, false));
rect.y += widget_height + vpadding;

const std::vector<int> buttonids = { 1 };
const std::vector<std::string> buttonlabels = { "cancel" };
_buttons.populate(_renderer, buttonlabels, buttonids, static_cast<Sint32>(total_height),
static_cast<Sint32>(widget_width / 2), static_cast<Sint32>(widget_height));

SDL_ShowWindow(_window);
SDL_RaiseWindow(_window);

return true;
}

void SDLConnectionDialog::destroyWindow()
{
_buttons.clear();
_list.clear();
SDL_DestroyRenderer(_renderer);
SDL_DestroyWindow(_window);
_renderer = nullptr;
_window = nullptr;
}

bool SDLConnectionDialog::show(MsgType type, const char* fmt, va_list ap)
{
std::lock_guard lock(_mux);
_msg = print(fmt, ap);
return show(type);
}

bool SDLConnectionDialog::show(MsgType type)
{
_type = type;
return sdl_push_user_event(SDL_USEREVENT_RETRY_DIALOG);
}

std::string SDLConnectionDialog::print(const char* fmt, va_list ap)
{
int size = -1;
std::string res;

do
{
res.resize(128);
if (size > 0)
res.resize(size);

va_list copy;
va_copy(copy, ap);
size = vsnprintf(res.data(), res.size(), fmt, copy);
va_end(copy);

} while ((size > 0) && (size > res.size()));

return res;
}

bool SDLConnectionDialog::setTimer(Uint32 timeoutMS)
{
std::lock_guard lock(_mux);
resetTimer();

_timer = SDL_AddTimer(timeoutMS, &SDLConnectionDialog::timeout, this);
_running = true;
return true;
}

void SDLConnectionDialog::resetTimer()
{
if (_running)
SDL_RemoveTimer(_timer);
_running = false;
}

Uint32 SDLConnectionDialog::timeout(Uint32 intervalMS, void* pvthis)
{
auto ths = static_cast<SDLConnectionDialog*>(pvthis);
ths->hide();
ths->_running = false;
return 0;
}

0 comments on commit e1de32f

Please sign in to comment.