From 877b31b33e63c8a9df2649daedfb26a24d2e4515 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 20:51:53 -0500 Subject: [PATCH 1/8] software_keyboard: Signal state changed event upon construction Previously, ILibraryAppletAccessor would signal upon creation of any applet, but this is incorrect. A flag inside of the applet code determines whether or not creation should signal state change and swkbd happens to be one of these applets. --- src/core/hle/service/am/applets/software_keyboard.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 981bdec51..40984ffa9 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -38,7 +38,12 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( return params; } -SoftwareKeyboard::SoftwareKeyboard() = default; +SoftwareKeyboard::SoftwareKeyboard() { + // Some applets require this to be signalled on applet creation, some do not. Internally, this + // is done by a flag in the applet module, but for simplicity SoftwareKeyboard is one of the + // applets with this flag. + broker.SignalStateChanged(); +} SoftwareKeyboard::~SoftwareKeyboard() = default; From d17f38494b8d64c16ac718c660a57cd89ab48b6f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 20:58:51 -0500 Subject: [PATCH 2/8] frontend: Add frontend applet for ProfileSelect Responsible for selecting a profile and firing callback upon completion. --- src/core/CMakeLists.txt | 2 ++ src/core/frontend/applets/profile_select.cpp | 19 ++++++++++++++ src/core/frontend/applets/profile_select.h | 27 ++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/core/frontend/applets/profile_select.cpp create mode 100644 src/core/frontend/applets/profile_select.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 73aec8ab0..4b51943ab 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -79,6 +79,8 @@ add_library(core STATIC file_sys/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h + frontend/applets/profile_select.cpp + frontend/applets/profile_select.h frontend/applets/software_keyboard.cpp frontend/applets/software_keyboard.h frontend/emu_window.cpp diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp new file mode 100644 index 000000000..fbf5f2a9e --- /dev/null +++ b/src/core/frontend/applets/profile_select.cpp @@ -0,0 +1,19 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/frontend/applets/profile_select.h" +#include "core/settings.h" + +namespace Core::Frontend { + +ProfileSelectApplet::~ProfileSelectApplet() = default; + +void DefaultProfileSelectApplet::SelectProfile( + std::function)> callback) const { + Service::Account::ProfileManager manager; + callback(manager.GetUser(Settings::values.current_user).value_or(Service::Account::UUID{})); + LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h new file mode 100644 index 000000000..fc8f7ae94 --- /dev/null +++ b/src/core/frontend/applets/profile_select.h @@ -0,0 +1,27 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "core/hle/service/acc/profile_manager.h" + +namespace Core::Frontend { + +class ProfileSelectApplet { +public: + virtual ~ProfileSelectApplet(); + + virtual void SelectProfile( + std::function)> callback) const = 0; +}; + +class DefaultProfileSelectApplet final : public ProfileSelectApplet { +public: + void SelectProfile( + std::function)> callback) const override; +}; + +} // namespace Core::Frontend From 58fd0a1c50912f28457eae974dfe928463ceb0c2 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 21:00:04 -0500 Subject: [PATCH 3/8] core: Add getter/setter for ProfileSelector in System --- src/core/core.cpp | 11 +++++++++++ src/core/core.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/src/core/core.cpp b/src/core/core.cpp index 795fabc65..19b4b97c5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -97,6 +97,8 @@ struct System::Impl { virtual_filesystem = std::make_shared(); /// Create default implementations of applets if one is not provided. + if (profile_selector == nullptr) + profile_selector = std::make_unique(); if (software_keyboard == nullptr) software_keyboard = std::make_unique(); @@ -227,6 +229,7 @@ struct System::Impl { bool is_powered_on = false; /// Frontend applets + std::unique_ptr profile_selector; std::unique_ptr software_keyboard; /// Service manager @@ -422,6 +425,14 @@ std::shared_ptr System::GetFilesystem() const { return impl->virtual_filesystem; } +void System::SetProfileSelector(std::unique_ptr applet) { + impl->profile_selector = std::move(applet); +} + +const Core::Frontend::ProfileSelectApplet& System::GetProfileSelector() const { + return *impl->profile_selector; +} + void System::SetSoftwareKeyboard(std::unique_ptr applet) { impl->software_keyboard = std::move(applet); } diff --git a/src/core/core.h b/src/core/core.h index be71bd437..21dea051b 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "core/hle/kernel/object.h" +#include "frontend/applets/profile_select.h" namespace Core::Frontend { class EmuWindow; @@ -237,6 +238,10 @@ public: std::shared_ptr GetFilesystem() const; + void SetProfileSelector(std::unique_ptr applet); + + const Core::Frontend::ProfileSelectApplet& GetProfileSelector() const; + void SetSoftwareKeyboard(std::unique_ptr applet); const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const; From 6deccc7e6b7a242c94e4e54cc805c5ee390a5284 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 21:00:42 -0500 Subject: [PATCH 4/8] qt: Register to use Qt ProfileSelector instead of default --- src/yuzu/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 22c207a3a..b39bf1903 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -8,6 +8,7 @@ #include // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. +#include "applets/profile_select.h" #include "applets/software_keyboard.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" @@ -571,6 +572,7 @@ bool GMainWindow::LoadROM(const QString& filename) { system.SetGPUDebugContext(debug_context); + system.SetProfileSelector(std::make_unique(*this)); system.SetSoftwareKeyboard(std::make_unique(*this)); const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; From 4fb59fdfe1e5fe2d0b9313c395e0d7c880e00c6f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 21:02:36 -0500 Subject: [PATCH 5/8] applets: Implement ProfileSelect applet Allows the player to select an emulated profile. --- .../hle/service/am/applets/profile_select.cpp | 76 +++++++++++++++++++ .../hle/service/am/applets/profile_select.h | 54 +++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 src/core/hle/service/am/applets/profile_select.cpp create mode 100644 src/core/hle/service/am/applets/profile_select.h diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp new file mode 100644 index 000000000..750f0fdeb --- /dev/null +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -0,0 +1,76 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/assert.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/profile_select.h" + +namespace Service::AM::Applets { + +constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; + +ProfileSelect::ProfileSelect() = default; +ProfileSelect::~ProfileSelect() = default; + +void ProfileSelect::Initialize() { + complete = false; + status = RESULT_SUCCESS; + final_data.clear(); + + Applet::Initialize(); + + const auto user_config_storage = broker.PopNormalDataToApplet(); + ASSERT(user_config_storage != nullptr); + const auto& user_config = user_config_storage->GetData(); + + ASSERT(user_config.size() >= sizeof(UserSelectionConfig)); + std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig)); +} + +bool ProfileSelect::TransactionComplete() const { + return complete; +} + +ResultCode ProfileSelect::GetStatus() const { + return status; +} + +void ProfileSelect::ExecuteInteractive() { + UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); +} + +void ProfileSelect::Execute() { + if (complete) { + broker.PushNormalDataFromApplet(IStorage{final_data}); + return; + } + + const auto& frontend{Core::System::GetInstance().GetProfileSelector()}; + + frontend.SelectProfile([this](std::optional uuid) { SelectionComplete(uuid); }); +} + +void ProfileSelect::SelectionComplete(std::optional uuid) { + UserSelectionOutput output{}; + + if (uuid.has_value() && uuid->uuid != Account::INVALID_UUID) { + output.result = 0; + output.uuid_selected = uuid->uuid; + } else { + status = ERR_USER_CANCELLED_SELECTION; + output.result = ERR_USER_CANCELLED_SELECTION.raw; + output.uuid_selected = Account::INVALID_UUID; + } + + final_data = std::vector(sizeof(UserSelectionOutput)); + std::memcpy(final_data.data(), &output, final_data.size()); + broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h new file mode 100644 index 000000000..c383527f4 --- /dev/null +++ b/src/core/hle/service/am/applets/profile_select.h @@ -0,0 +1,54 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/common_funcs.h" +#include "common/swap.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +struct UserSelectionConfig { + // TODO(DarkLordZach): RE this structure + // It seems to be flags and the like that determine the UI of the applet on the switch... from + // my research this is safe to ignore for now. + INSERT_PADDING_BYTES(0xA0); +}; +static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size."); + +struct UserSelectionOutput { + u64 result; + u128 uuid_selected; +}; +static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size."); + +class ProfileSelect final : public Applet { +public: + ProfileSelect(); + ~ProfileSelect() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void SelectionComplete(std::optional uuid); + +private: + UserSelectionConfig config; + bool complete = false; + ResultCode status = RESULT_SUCCESS; + std::vector final_data; +}; + +} // namespace Service::AM::Applets From 60b59d554d20c4f02036f254604835c62a7f282f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 21:02:57 -0500 Subject: [PATCH 6/8] am: Use ProfileSelect applet --- src/core/hle/service/am/am.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 3a7b6da84..1a15d85cb 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -19,6 +19,7 @@ #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/applets/profile_select.h" #include "core/hle/service/am/applets/software_keyboard.h" #include "core/hle/service/am/applets/stub_applet.h" #include "core/hle/service/am/idle.h" @@ -39,6 +40,7 @@ constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; enum class AppletId : u32 { + ProfileSelect = 0x10, SoftwareKeyboard = 0x11, }; @@ -773,6 +775,8 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default; static std::shared_ptr GetAppletFromId(AppletId id) { switch (id) { + case AppletId::ProfileSelect: + return std::make_shared(); case AppletId::SoftwareKeyboard: return std::make_shared(); default: From bf90f2402dae06ebf4292e59bf8703490596f6ba Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 21:03:33 -0500 Subject: [PATCH 7/8] qt: Implement GUI dialog frontend for ProfileSelector Presents profiles in a list, similar to switch. --- src/core/CMakeLists.txt | 2 + src/yuzu/CMakeLists.txt | 2 + src/yuzu/applets/profile_select.cpp | 168 ++++++++++++++++++++++++++++ src/yuzu/applets/profile_select.h | 73 ++++++++++++ src/yuzu/main.cpp | 22 ++++ src/yuzu/main.h | 2 + 6 files changed, 269 insertions(+) create mode 100644 src/yuzu/applets/profile_select.cpp create mode 100644 src/yuzu/applets/profile_select.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4b51943ab..4f0ea5d67 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -160,6 +160,8 @@ add_library(core STATIC hle/service/am/applet_oe.h hle/service/am/applets/applets.cpp hle/service/am/applets/applets.h + hle/service/am/applets/profile_select.cpp + hle/service/am/applets/profile_select.h hle/service/am/applets/software_keyboard.cpp hle/service/am/applets/software_keyboard.h hle/service/am/applets/stub_applet.cpp diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index cfca8f4a8..61562b9b2 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -7,6 +7,8 @@ add_executable(yuzu Info.plist about_dialog.cpp about_dialog.h + applets/profile_select.cpp + applets/profile_select.h applets/software_keyboard.cpp applets/software_keyboard.h bootmanager.cpp diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp new file mode 100644 index 000000000..5c1b65a2c --- /dev/null +++ b/src/yuzu/applets/profile_select.cpp @@ -0,0 +1,168 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include +#include "common/file_util.h" +#include "common/string_util.h" +#include "core/hle/lock.h" +#include "yuzu/applets/profile_select.h" +#include "yuzu/main.h" + +// Same backup JPEG used by acc IProfile::GetImage if no jpeg found +constexpr std::array backup_jpeg{ + 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, + 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, + 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, + 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, + 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, +}; + +QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) { + return QtProfileSelectionDialog::tr( + "%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. " + "00112233-4455-6677-8899-AABBCCDDEEFF))") + .arg(username, QString::fromStdString(uuid.FormatSwitch())); +} + +QString GetImagePath(Service::Account::UUID uuid) { + const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + + "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; + return QString::fromStdString(path); +} + +QPixmap GetIcon(Service::Account::UUID uuid) { + QPixmap icon{GetImagePath(uuid)}; + + if (!icon) { + icon.fill(Qt::black); + icon.loadFromData(backup_jpeg.data(), static_cast(backup_jpeg.size())); + } + + return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); +} + +QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent) + : QDialog(parent), profile_manager(std::make_unique()) { + outer_layout = new QVBoxLayout; + + instruction_label = new QLabel(tr("Select a user:")); + + scroll_area = new QScrollArea; + + buttons = new QDialogButtonBox; + buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); + buttons->addButton(tr("OK"), QDialogButtonBox::AcceptRole); + + connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject); + + outer_layout->addWidget(instruction_label); + outer_layout->addWidget(scroll_area); + outer_layout->addWidget(buttons); + + layout = new QVBoxLayout; + tree_view = new QTreeView; + item_model = new QStandardItemModel(tree_view); + tree_view->setModel(item_model); + + tree_view->setAlternatingRowColors(true); + tree_view->setSelectionMode(QHeaderView::SingleSelection); + tree_view->setSelectionBehavior(QHeaderView::SelectRows); + tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel); + tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel); + tree_view->setSortingEnabled(true); + tree_view->setEditTriggers(QHeaderView::NoEditTriggers); + tree_view->setUniformRowHeights(true); + tree_view->setIconSize({64, 64}); + tree_view->setContextMenuPolicy(Qt::NoContextMenu); + + item_model->insertColumns(0, 1); + item_model->setHeaderData(0, Qt::Horizontal, "Users"); + + // We must register all custom types with the Qt Automoc system so that we are able to use it + // with signals/slots. In this case, QList falls under the umbrells of custom types. + qRegisterMetaType>("QList"); + + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(tree_view); + + scroll_area->setLayout(layout); + + connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser); + + const auto& profiles = profile_manager->GetAllUsers(); + for (const auto& user : profiles) { + Service::Account::ProfileBase profile; + if (!profile_manager->GetProfileBase(user, profile)) + continue; + + const auto username = Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast(profile.username.data()), profile.username.size()); + + list_items.push_back(QList{new QStandardItem{ + GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}}); + } + + for (const auto& item : list_items) + item_model->appendRow(item); + + setLayout(outer_layout); + setWindowTitle(tr("Profile Selector")); + resize(550, 400); +} + +QtProfileSelectionDialog::~QtProfileSelectionDialog() = default; + +void QtProfileSelectionDialog::accept() { + ok = true; + QDialog::accept(); +} + +void QtProfileSelectionDialog::reject() { + ok = false; + user_index = 0; + QDialog::reject(); +} + +bool QtProfileSelectionDialog::GetStatus() const { + return ok; +} + +u32 QtProfileSelectionDialog::GetIndex() const { + return user_index; +} + +void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) { + user_index = index.row(); +} + +QtProfileSelector::QtProfileSelector(GMainWindow& parent) { + connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent, + &GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection); + connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this, + &QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection); +} + +QtProfileSelector::~QtProfileSelector() = default; + +void QtProfileSelector::SelectProfile( + std::function)> callback) const { + this->callback = std::move(callback); + emit MainWindowSelectProfile(); +} + +void QtProfileSelector::MainWindowFinishedSelection(std::optional uuid) { + // Acquire the HLE mutex + std::lock_guard lock(HLE::g_hle_lock); + callback(uuid); +} diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/profile_select.h new file mode 100644 index 000000000..9acb092f3 --- /dev/null +++ b/src/yuzu/applets/profile_select.h @@ -0,0 +1,73 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "core/frontend/applets/profile_select.h" + +class GMainWindow; +class QDialogButtonBox; +class QGraphicsScene; +class QLabel; +class QScrollArea; +class QStandardItem; +class QStandardItemModel; +class QTreeView; +class QVBoxLayout; + +class QtProfileSelectionDialog final : public QDialog { + Q_OBJECT + +public: + QtProfileSelectionDialog(QWidget* parent); + ~QtProfileSelectionDialog() override; + + void accept() override; + void reject() override; + + bool GetStatus() const; + u32 GetIndex() const; + +private: + bool ok = false; + u32 user_index = 0; + + void SelectUser(const QModelIndex& index); + + QVBoxLayout* layout; + QTreeView* tree_view; + QStandardItemModel* item_model; + QGraphicsScene* scene; + + std::vector> list_items; + + QVBoxLayout* outer_layout; + QLabel* instruction_label; + QScrollArea* scroll_area; + QDialogButtonBox* buttons; + + std::unique_ptr profile_manager; +}; + +class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet { + Q_OBJECT + +public: + explicit QtProfileSelector(GMainWindow& parent); + ~QtProfileSelector() override; + + void SelectProfile( + std::function)> callback) const override; + +signals: + void MainWindowSelectProfile() const; + +private: + void MainWindowFinishedSelection(std::optional uuid); + + mutable std::function)> callback; +}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b39bf1903..085cab74b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -208,6 +208,28 @@ GMainWindow::~GMainWindow() { delete render_window; } +void GMainWindow::ProfileSelectorSelectProfile() { + QtProfileSelectionDialog dialog(this); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + dialog.exec(); + + if (!dialog.GetStatus()) { + emit ProfileSelectorFinishedSelection(std::nullopt); + return; + } + + Service::Account::ProfileManager manager; + const auto uuid = manager.GetUser(dialog.GetIndex()); + if (!uuid.has_value()) { + emit ProfileSelectorFinishedSelection(std::nullopt); + return; + } + + emit ProfileSelectorFinishedSelection(uuid); +} + void GMainWindow::SoftwareKeyboardGetText( const Core::Frontend::SoftwareKeyboardParameters& parameters) { QtSoftwareKeyboardDialog dialog(this, parameters); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 674e73412..7c5eaf16b 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -99,10 +99,12 @@ signals: // Signal that tells widgets to update icons to use the current theme void UpdateThemedIcons(); + void ProfileSelectorFinishedSelection(std::optional uuid); void SoftwareKeyboardFinishedText(std::optional text); void SoftwareKeyboardFinishedCheckDialog(); public slots: + void ProfileSelectorSelectProfile(); void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); From e11e65b3d63fabd7c953cca07971364984021c3e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 23 Nov 2018 11:00:33 -0500 Subject: [PATCH 8/8] applets: Correct event ResetTypes from OneShot to Sticky Fixes bugs relating to signalling in software keyboard. --- src/core/hle/service/am/applets/applets.cpp | 6 +++--- src/core/hle/service/am/applets/profile_select.cpp | 1 + src/core/hle/service/am/applets/profile_select.h | 4 ---- src/core/hle/service/am/applets/software_keyboard.cpp | 7 +------ src/yuzu/applets/profile_select.h | 2 +- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 47da35537..7698ca819 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -16,11 +16,11 @@ namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker() { auto& kernel = Core::System::GetInstance().Kernel(); state_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent"); + kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent"); pop_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent"); + kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent"); pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); + kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } AppletDataBroker::~AppletDataBroker() = default; diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 750f0fdeb..4c7b45454 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include + #include "common/assert.h" #include "common/string_util.h" #include "core/core.h" diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h index c383527f4..787485f22 100644 --- a/src/core/hle/service/am/applets/profile_select.h +++ b/src/core/hle/service/am/applets/profile_select.h @@ -4,14 +4,10 @@ #pragma once -#include -#include #include #include "common/common_funcs.h" -#include "common/swap.h" #include "core/hle/service/acc/profile_manager.h" -#include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 40984ffa9..981bdec51 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -38,12 +38,7 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( return params; } -SoftwareKeyboard::SoftwareKeyboard() { - // Some applets require this to be signalled on applet creation, some do not. Internally, this - // is done by a flag in the applet module, but for simplicity SoftwareKeyboard is one of the - // applets with this flag. - broker.SignalStateChanged(); -} +SoftwareKeyboard::SoftwareKeyboard() = default; SoftwareKeyboard::~SoftwareKeyboard() = default; diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/profile_select.h index 9acb092f3..868573324 100644 --- a/src/yuzu/applets/profile_select.h +++ b/src/yuzu/applets/profile_select.h @@ -23,7 +23,7 @@ class QtProfileSelectionDialog final : public QDialog { Q_OBJECT public: - QtProfileSelectionDialog(QWidget* parent); + explicit QtProfileSelectionDialog(QWidget* parent); ~QtProfileSelectionDialog() override; void accept() override;