Compare commits

..

27 Commits

Author SHA1 Message Date
bunnei
781c85b951 hle: service: sm: Remove redundant session reservation, etc.
- We were double-reserving, causing us to run out of sessions in Pokemon Sword & Shield.
2021-06-10 11:34:41 -07:00
bunnei
fa8a0065ca hle: service: Increase arbitrary max sessions limit.
- Pokemon Sword/Shield are still hitting this for some reason, causing an svcBreak.
2021-06-10 00:08:09 -07:00
bunnei
74f0087bfa Merge pull request #6441 from bunnei/fix-session-handler
hle: kernel: KServerSession: Fix client disconnected.
2021-06-09 22:53:25 -07:00
bunnei
b259e95c09 hle: kernel: KClientPort: Add an assert for session count.
- Prevents us from over decrementing num_sessions.
2021-06-09 22:36:42 -07:00
bunnei
ec5674a6ad hle: service: sm: Fix GetService setup of session & port. 2021-06-09 22:29:18 -07:00
bunnei
2aa6a8d889 hle: service: Use correct size for ServerSessionCountMax. 2021-06-09 22:04:36 -07:00
bunnei
b2971b48ed hle: kernel: KServerSession: Fix client disconnected.
- Prevents a cloned session's handler from being overwritten by another disconnected session.
- Fixes session handler nullptr asserts with Pokemon Sword & Shield.
2021-06-09 21:37:11 -07:00
Ameer J
86d832ab9a Merge pull request #6439 from lat9nq/ci-no-7z
ci: common: Remove 7z packaging
2021-06-09 19:47:08 -04:00
Mai M
61c7a81ec8 Merge pull request #6440 from bunnei/cancel-synch
kernel: svc: Add missing error check to CancelSynchronization.
2021-06-09 19:08:36 -04:00
lat9nq
fbad68de0f ci: windows: Compress using xz
Use XZ instead of gzip for packing. Should save about 10 MB.
2021-06-09 18:54:23 -04:00
bunnei
c63ea608aa kernel: svc: Add missing error check to CancelSynchronization.
- Avoids a potential crash if the handle is invalid, and also makes this code accurate to real kernel behavior.
2021-06-09 15:24:46 -07:00
lat9nq
6eeb532c96 ci: common: Remove 7z packaging
Removes the 7z from being package during CI, as only .tar.xz preserves
information needed on Linux, and otherwise is just extremely redundant
to package in addition to the .tar.xz.  This affects Linux releases and
PR-verify artifacts only. MSVC releases do not use this script to my
knowledge.
2021-06-09 17:16:29 -04:00
Mai M
5857067a18 Merge pull request #6436 from liushuyu/master
src/common/CMakeLists.txt: fix variable escaping
2021-06-09 15:38:56 -04:00
bunnei
2d32fc2318 hle: service: Increase arbitrary max sessions limit.
- Pokemon Sword/Shield are still hitting this for some reason, causing an svcBreak.
2021-06-09 11:59:34 -07:00
bunnei
75a4ac12c6 Merge pull request #6413 from Kewlan/limitable_input_dialog_limit
limitable_input_dialog: Implement character limiter
2021-06-09 11:55:36 -07:00
liushuyu
eb9deffab6 src/common/CMakeLists.txt: fix variable escaping 2021-06-09 02:20:55 -06:00
Morph
15483c07c6 Merge pull request #6435 from lioncash/nodisc2
common/fs/path_util: Remove [[nodiscard]] from function with void return
2021-06-09 02:44:41 -04:00
bunnei
f9c3e2e872 Merge pull request #6434 from lioncash/tcontext
configure_ui: Add translation context for file-scope strings
2021-06-08 19:36:44 -07:00
bunnei
3c621d37f0 Merge pull request #6428 from bunnei/service-thread-crash-fix
hle: kernel: Remove service thread manager and use weak_ptr.
2021-06-08 16:43:55 -07:00
Lioncash
dd8577e91d common/fs/path_util: Remove [[nodiscard]] from function with void return
We can't make use of the return value here, since we don't a return
value to work with.
2021-06-08 19:36:09 -04:00
Lioncash
b3eb08254b configure_ui: Add translation context for file-scope strings
Allows for these strings to show up in the translation files.
2021-06-08 19:33:23 -04:00
Mai M
f09c9b5fcc Merge pull request #6426 from lat9nq/context-menu-start
yuzu qt: Start games from context menu
2021-06-08 17:09:25 -04:00
bunnei
3b5673daca Merge pull request #6412 from clementgallet/yuzu-cmd-window-gl
yuzu-cmd: Fix OpenGL rendering
2021-06-07 21:12:17 -07:00
lat9nq
5ac018d1df yuzu qt: Start games from context menu
This connects the BootGame function to the context menu. In addition,
there is an option to boot without using the custom configuration.
2021-06-07 20:27:51 -04:00
Kewlan
058196a089 limitable_input_dialog: Implement character limiter
When using GetText() you can now choose what set of characters the user can't enter.
2021-06-06 09:07:55 +02:00
Clément Gallet
2e1c58b905 Avoid -Wshadow warning
Co-authored-by: Mai M. <mathew1800@gmail.com>
2021-06-05 18:43:10 +02:00
Clément Gallet
9ff8504452 yuzu-cmd: Fix OpenGL rendering 2021-06-04 11:39:04 +02:00
20 changed files with 146 additions and 84 deletions

View File

@@ -9,11 +9,5 @@ cp "${REV_NAME}-source.tar.xz" "$DIR_NAME"
tar $COMPRESSION_FLAGS "$ARCHIVE_NAME" "$DIR_NAME"
mv "$DIR_NAME" $RELEASE_NAME
mv "${REV_NAME}-source.tar.xz" $RELEASE_NAME
7z a "$REV_NAME.7z" $RELEASE_NAME
# move the compiled archive into the artifacts directory to be uploaded by travis releases
mv "$ARCHIVE_NAME" "${ARTIFACTS_DIR}/"
mv "$REV_NAME.7z" "${ARTIFACTS_DIR}/"

View File

@@ -3,8 +3,8 @@
. .ci/scripts/common/pre-upload.sh
REV_NAME="yuzu-windows-mingw-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
ARCHIVE_NAME="${REV_NAME}.tar.xz"
COMPRESSION_FLAGS="-cJvf"
if [ "${RELEASE_NAME}" = "mainline" ]; then
DIR_NAME="${REV_NAME}"

View File

@@ -21,14 +21,14 @@ find_package(Git QUIET)
add_custom_command(OUTPUT scm_rev.cpp
COMMAND ${CMAKE_COMMAND}
-DSRC_DIR="${CMAKE_SOURCE_DIR}"
-DBUILD_REPOSITORY="${BUILD_REPOSITORY}"
-DTITLE_BAR_FORMAT_IDLE="${TITLE_BAR_FORMAT_IDLE}"
-DTITLE_BAR_FORMAT_RUNNING="${TITLE_BAR_FORMAT_RUNNING}"
-DBUILD_TAG="${BUILD_TAG}"
-DBUILD_ID="${DISPLAY_VERSION}"
-DGIT_EXECUTABLE="${GIT_EXECUTABLE}"
-P "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
-DSRC_DIR=${CMAKE_SOURCE_DIR}
-DBUILD_REPOSITORY=${BUILD_REPOSITORY}
-DTITLE_BAR_FORMAT_IDLE=${TITLE_BAR_FORMAT_IDLE}
-DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
-DBUILD_TAG=${BUILD_TAG}
-DBUILD_ID=${DISPLAY_VERSION}
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
-P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
DEPENDS
# WARNING! It was too much work to try and make a common location for this list,
# so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well
@@ -92,6 +92,7 @@ add_custom_command(OUTPUT scm_rev.cpp
"${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
# technically we should regenerate if the git version changed, but its not worth the effort imo
"${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
VERBATIM
)
add_library(common STATIC

View File

@@ -209,7 +209,7 @@ void SetYuzuPath(YuzuPath yuzu_path, const std::filesystem::path& new_path);
#ifdef _WIN32
template <typename Path>
[[nodiscard]] void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
void SetYuzuPath(YuzuPath yuzu_path, const Path& new_path) {
if constexpr (IsChar<typename Path::value_type>) {
SetYuzuPath(yuzu_path, ToU8String(new_path));
} else {

View File

@@ -57,11 +57,11 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
}
void SessionRequestHandler::ClientConnected(KServerSession* session) {
session->SetSessionHandler(shared_from_this());
session->ClientConnected(shared_from_this());
}
void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
session->SetSessionHandler(nullptr);
session->ClientDisconnected();
}
HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,

View File

@@ -28,6 +28,9 @@ void KClientPort::Initialize(KPort* parent_port_, s32 max_sessions_, std::string
void KClientPort::OnSessionFinalized() {
KScopedSchedulerLock sl{kernel};
// This might happen if a session was improperly used with this port.
ASSERT_MSG(num_sessions > 0, "num_sessions is invalid");
const auto prev = num_sessions--;
if (prev == max_sessions) {
this->NotifyAvailable();
@@ -66,7 +69,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out,
// Update the session counts.
{
// Atomically increment the number of sessions.
s32 new_sessions;
s32 new_sessions{};
{
const auto max = max_sessions;
auto cur_sessions = num_sessions.load(std::memory_order_acquire);

View File

@@ -62,15 +62,14 @@ public:
void OnClientClosed();
/**
* Sets the HLE handler for the session. This handler will be called to service IPC requests
* instead of the regular IPC machinery. (The regular IPC machinery is currently not
* implemented.)
*/
void SetSessionHandler(SessionRequestHandlerPtr handler) {
void ClientConnected(SessionRequestHandlerPtr handler) {
manager->SetSessionHandler(std::move(handler));
}
void ClientDisconnected() {
manager = nullptr;
}
/**
* Handle a sync request from the emulated application.
*

View File

@@ -449,8 +449,8 @@ static ResultCode CancelSynchronization(Core::System& system, Handle handle) {
// Get the thread from its handle.
KScopedAutoObject thread =
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
static_cast<Handle>(handle));
system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Cancel the thread's wait.
thread->WaitCancel();

View File

@@ -40,9 +40,11 @@ namespace SM {
class ServiceManager;
}
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
/// Arbitrary default number of maximum connections to an HLE service.
static const u32 DefaultMaxSessions = 64;
/// Default number of maximum connections to a server session.
static constexpr u32 ServerSessionCountMax = 0x40;
static_assert(ServerSessionCountMax == 0x40,
"ServerSessionCountMax isn't 0x40 somehow, this assert is a reminder that this will "
"break lots of things");
/**
* This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it
@@ -178,7 +180,7 @@ protected:
* connected to this service at the same time.
*/
explicit ServiceFramework(Core::System& system_, const char* service_name_,
u32 max_sessions_ = DefaultMaxSessions)
u32 max_sessions_ = ServerSessionCountMax)
: ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
/// Registers handlers in the service.

View File

@@ -151,31 +151,23 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
std::string name(PopServiceName(rp));
// Find the named port.
auto result = service_manager.GetServicePort(name);
if (result.Failed()) {
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
return result.Code();
auto port_result = service_manager.GetServicePort(name);
if (port_result.Failed()) {
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
return port_result.Code();
}
auto* port = result.Unwrap();
// Reserve a new session from the process resource limit.
Kernel::KScopedResourceReservation session_reservation(
kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached);
auto& port = port_result.Unwrap()->GetClientPort();
// Create a new session.
auto* session = Kernel::KSession::Create(kernel);
session->Initialize(&port->GetClientPort(), std::move(name));
// Commit the session reservation.
session_reservation.Commit();
// Enqueue the session with the named port.
port->EnqueueSession(&session->GetServerSession());
Kernel::KClientSession* session{};
if (const auto result = port.CreateSession(std::addressof(session)); result.IsError()) {
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
return result;
}
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
return MakeResult(&session->GetClientSession());
return MakeResult(session);
}
void SM::RegisterService(Kernel::HLERequestContext& ctx) {

View File

@@ -1395,7 +1395,8 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
void ConfigureInputPlayer::CreateProfile() {
const auto profile_name =
LimitableInputDialog::GetText(this, tr("New Profile"), tr("Enter a profile name:"), 1, 20);
LimitableInputDialog::GetText(this, tr("New Profile"), tr("Enter a profile name:"), 1, 20,
LimitableInputDialog::InputLimiter::Filesystem);
if (profile_name.isEmpty()) {
return;

View File

@@ -17,17 +17,30 @@
namespace {
constexpr std::array default_icon_sizes{
std::make_pair(0, QT_TR_NOOP("None")),
std::make_pair(32, QT_TR_NOOP("Small (32x32)")),
std::make_pair(64, QT_TR_NOOP("Standard (64x64)")),
std::make_pair(128, QT_TR_NOOP("Large (128x128)")),
std::make_pair(256, QT_TR_NOOP("Full Size (256x256)")),
std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
std::make_pair(32, QT_TRANSLATE_NOOP("ConfigureUI", "Small (32x32)")),
std::make_pair(64, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (64x64)")),
std::make_pair(128, QT_TRANSLATE_NOOP("ConfigureUI", "Large (128x128)")),
std::make_pair(256, QT_TRANSLATE_NOOP("ConfigureUI", "Full Size (256x256)")),
};
// clang-format off
constexpr std::array row_text_names{
QT_TR_NOOP("Filename"), QT_TR_NOOP("Filetype"), QT_TR_NOOP("Title ID"),
QT_TR_NOOP("Title Name"), QT_TR_NOOP("None"),
QT_TRANSLATE_NOOP("ConfigureUI", "Filename"),
QT_TRANSLATE_NOOP("ConfigureUI", "Filetype"),
QT_TRANSLATE_NOOP("ConfigureUI", "Title ID"),
QT_TRANSLATE_NOOP("ConfigureUI", "Title Name"),
QT_TRANSLATE_NOOP("ConfigureUI", "None"),
};
// clang-format on
QString GetTranslatedIconSize(size_t index) {
return QCoreApplication::translate("ConfigureUI", default_icon_sizes[index].second);
}
QString GetTranslatedRowTextName(size_t index) {
return QCoreApplication::translate("ConfigureUI", row_text_names[index]);
}
} // Anonymous namespace
ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) {
@@ -121,11 +134,11 @@ void ConfigureUi::RetranslateUI() {
ui->retranslateUi(this);
for (int i = 0; i < ui->icon_size_combobox->count(); i++) {
ui->icon_size_combobox->setItemText(i, tr(default_icon_sizes[i].second));
ui->icon_size_combobox->setItemText(i, GetTranslatedIconSize(static_cast<size_t>(i)));
}
for (int i = 0; i < ui->row_1_text_combobox->count(); i++) {
const QString name = tr(row_text_names[i]);
const QString name = GetTranslatedRowTextName(static_cast<size_t>(i));
ui->row_1_text_combobox->setItemText(i, name);
ui->row_2_text_combobox->setItemText(i, name);
@@ -152,8 +165,9 @@ void ConfigureUi::InitializeLanguageComboBox() {
}
void ConfigureUi::InitializeIconSizeComboBox() {
for (const auto& size : default_icon_sizes) {
ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first);
for (size_t i = 0; i < default_icon_sizes.size(); i++) {
const auto size = default_icon_sizes[i].first;
ui->icon_size_combobox->addItem(GetTranslatedIconSize(i), size);
}
}
@@ -170,7 +184,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
ui->row_1_text_combobox->clear();
for (std::size_t i = 0; i < row_text_names.size(); i++) {
const QString row_text_name = QString::fromUtf8(row_text_names[i]);
const QString row_text_name = GetTranslatedRowTextName(i);
ui->row_1_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}
@@ -189,7 +203,7 @@ void ConfigureUi::UpdateSecondRowComboBox(bool init) {
ui->row_2_text_combobox->clear();
for (std::size_t i = 0; i < row_text_names.size(); ++i) {
const QString row_text_name = QString::fromUtf8(row_text_names[i]);
const QString row_text_name = GetTranslatedRowTextName(i);
ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}

View File

@@ -505,6 +505,10 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) {
QAction* favorite = context_menu.addAction(tr("Favorite"));
context_menu.addSeparator();
QAction* start_game = context_menu.addAction(tr("Start Game"));
QAction* start_game_global =
context_menu.addAction(tr("Start Game without Custom Configuration"));
context_menu.addSeparator();
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
QAction* open_transferable_shader_cache =
@@ -540,6 +544,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
});
connect(start_game, &QAction::triggered, [this, path]() {
emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal);
});
connect(start_game_global, &QAction::triggered, [this, path]() {
emit BootGame(QString::fromStdString(path), 0, StartGameType::Global);
});
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
});

View File

@@ -28,6 +28,7 @@ class GameListWorker;
class GameListSearchField;
class GameListDir;
class GMainWindow;
enum class StartGameType;
namespace FileSys {
class ManualContentProvider;
@@ -82,6 +83,7 @@ public:
static const QStringList supported_file_extensions;
signals:
void BootGame(const QString& game_path, std::size_t program_index, StartGameType type);
void GameChosen(const QString& game_path);
void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target,

View File

@@ -1094,6 +1094,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
}
void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame);
connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
@@ -1320,7 +1321,7 @@ void GMainWindow::SelectAndSetCurrentUser() {
Settings::values.current_user = dialog.GetIndex();
}
void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) {
LOG_INFO(Frontend, "yuzu starting...");
StoreRecentFile(filename); // Put the filename on top of the list
@@ -1332,7 +1333,8 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
const auto loader = Loader::GetLoader(system, v_file, program_index);
if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
type == StartGameType::Normal) {
// Load per game settings
const auto file_path = std::filesystem::path{filename.toStdU16String()};
const auto config_file_name = title_id == 0

View File

@@ -39,6 +39,11 @@ class GameListPlaceholder;
class QtSoftwareKeyboardDialog;
enum class StartGameType {
Normal, // Can use custom configuration
Global, // Only uses global configuration
};
namespace Core::Frontend {
struct ControllerParameters;
struct InlineAppearParameters;
@@ -181,7 +186,8 @@ private:
void AllowOSSleep();
bool LoadROM(const QString& filename, std::size_t program_index);
void BootGame(const QString& filename, std::size_t program_index = 0);
void BootGame(const QString& filename, std::size_t program_index = 0,
StartGameType with_config = StartGameType::Normal);
void ShutdownGame();
void ShowTelemetryCallout();

View File

@@ -21,11 +21,13 @@ void LimitableInputDialog::CreateUI() {
text_label = new QLabel(this);
text_entry = new QLineEdit(this);
text_label_invalid = new QLabel(this);
buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
auto* const layout = new QVBoxLayout;
layout->addWidget(text_label);
layout->addWidget(text_entry);
layout->addWidget(text_label_invalid);
layout->addWidget(buttons);
setLayout(layout);
@@ -37,18 +39,36 @@ void LimitableInputDialog::ConnectEvents() {
}
QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
int min_character_limit, int max_character_limit) {
int min_character_limit, int max_character_limit,
InputLimiter limit_type) {
Q_ASSERT(min_character_limit <= max_character_limit);
LimitableInputDialog dialog{parent};
dialog.setWindowTitle(title);
dialog.text_label->setText(text);
dialog.text_entry->setMaxLength(max_character_limit);
dialog.text_label_invalid->show();
switch (limit_type) {
case InputLimiter::Filesystem:
dialog.invalid_characters = QStringLiteral("<>:;\"/\\|,.!?*");
break;
default:
dialog.invalid_characters.clear();
dialog.text_label_invalid->hide();
break;
}
dialog.text_label_invalid->setText(
tr("The text can't contain any of the following characters:\n%1")
.arg(dialog.invalid_characters));
auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
ok_button->setEnabled(false);
connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
ok_button->setEnabled(new_text.length() >= min_character_limit);
connect(dialog.text_entry, &QLineEdit::textEdited, [&] {
if (!dialog.invalid_characters.isEmpty()) {
dialog.RemoveInvalidCharacters();
}
ok_button->setEnabled(dialog.text_entry->text().length() >= min_character_limit);
});
if (dialog.exec() != QDialog::Accepted) {
@@ -57,3 +77,15 @@ QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, con
return dialog.text_entry->text();
}
void LimitableInputDialog::RemoveInvalidCharacters() {
auto cpos = text_entry->cursorPosition();
for (int i = 0; i < text_entry->text().length(); i++) {
if (invalid_characters.contains(text_entry->text().at(i))) {
text_entry->setText(text_entry->text().remove(i, 1));
i--;
cpos--;
}
}
text_entry->setCursorPosition(cpos);
}

View File

@@ -18,14 +18,24 @@ public:
explicit LimitableInputDialog(QWidget* parent = nullptr);
~LimitableInputDialog() override;
enum class InputLimiter {
None,
Filesystem,
};
static QString GetText(QWidget* parent, const QString& title, const QString& text,
int min_character_limit, int max_character_limit);
int min_character_limit, int max_character_limit,
InputLimiter limit_type = InputLimiter::None);
private:
void CreateUI();
void ConnectEvents();
void RemoveInvalidCharacters();
QString invalid_characters;
QLabel* text_label;
QLineEdit* text_entry;
QLabel* text_label_invalid;
QDialogButtonBox* buttons;
};

View File

@@ -32,17 +32,17 @@
class SDLGLContext : public Core::Frontend::GraphicsContext {
public:
explicit SDLGLContext() {
// create a hidden window to make the shared context against
window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
explicit SDLGLContext(SDL_Window* window_) : window{window_} {
context = SDL_GL_CreateContext(window);
}
~SDLGLContext() {
DoneCurrent();
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
}
void SwapBuffers() override {
SDL_GL_SwapWindow(window);
}
void MakeCurrent() override {
@@ -114,9 +114,6 @@ EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsyste
exit(1);
}
dummy_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0,
SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
SetWindowIcon();
if (fullscreen) {
@@ -159,5 +156,5 @@ EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() {
}
std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const {
return std::make_unique<SDLGLContext>();
return std::make_unique<SDLGLContext>(render_window);
}

View File

@@ -20,9 +20,6 @@ public:
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
private:
/// Fake hidden window for the core context
SDL_Window* dummy_window{};
/// Whether the GPU and driver supports the OpenGL extension required
bool SupportsRequiredGLExtensions();