-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
49936fc
commit e1de32f
Showing
11 changed files
with
572 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
Oops, something went wrong.