FullscreenUI: Use native file selector on Flatpak

This commit is contained in:
Stenzek 2024-05-12 20:22:37 +10:00
parent 37a76a020a
commit 522c2e3458
No known key found for this signature in database
7 changed files with 121 additions and 6 deletions

View File

@ -928,8 +928,8 @@ void FullscreenUI::DestroyResources()
ImGuiFullscreen::FileSelectorFilters FullscreenUI::GetDiscImageFilters() ImGuiFullscreen::FileSelectorFilters FullscreenUI::GetDiscImageFilters()
{ {
return {"*.bin", "*.cue", "*.iso", "*.img", "*.chd", "*.ecm", "*.mds", "*.psexe", return {"*.bin", "*.cue", "*.iso", "*.img", "*.chd", "*.ecm", "*.mds",
"*.ps-exe", "*.exe", "*.psf", "*.minipsf", "*.m3u", "*.pbp", "*.PBP"}; "*.psexe", "*.ps-exe", "*.exe", "*.psf", "*.minipsf", "*.m3u", "*.pbp"};
} }
void FullscreenUI::DoStartPath(std::string path, std::string state, std::optional<bool> fast_boot) void FullscreenUI::DoStartPath(std::string path, std::string state, std::optional<bool> fast_boot)

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "qthost.h" #include "qthost.h"
@ -36,6 +36,7 @@
#include "util/audio_stream.h" #include "util/audio_stream.h"
#include "util/http_downloader.h" #include "util/http_downloader.h"
#include "util/imgui_fullscreen.h"
#include "util/imgui_manager.h" #include "util/imgui_manager.h"
#include "util/ini_settings_interface.h" #include "util/ini_settings_interface.h"
#include "util/input_manager.h" #include "util/input_manager.h"
@ -1566,6 +1567,60 @@ void Host::OnCoverDownloaderOpenRequested()
emit g_emu_thread->onCoverDownloaderOpenRequested(); emit g_emu_thread->onCoverDownloaderOpenRequested();
} }
bool Host::ShouldPreferHostFileSelector()
{
#ifdef __linux__
// If running inside a flatpak, we want to use native selectors/portals.
return (std::getenv("container") != nullptr);
#else
return false;
#endif
}
void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directory, FileSelectorCallback callback,
FileSelectorFilters filters /* = FileSelectorFilters() */,
std::string_view initial_directory /* = std::string_view() */)
{
const bool from_cpu_thread = g_emu_thread->isOnThread();
QString filters_str;
if (!filters.empty())
{
filters_str.append(QStringLiteral("All File Types (%1)")
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
for (const std::string& filter : filters)
{
filters_str.append(
QStringLiteral(";;%1 Files (%2)")
.arg(
QtUtils::StringViewToQString(std::string_view(filter).substr(filter.starts_with("*.") ? 2 : 0)).toUpper())
.arg(QString::fromStdString(filter)));
}
}
QtHost::RunOnUIThread([title = QtUtils::StringViewToQString(title), select_directory, callback = std::move(callback),
filters_str = std::move(filters_str),
initial_directory = QtUtils::StringViewToQString(initial_directory),
from_cpu_thread]() mutable {
auto lock = g_main_window->pauseAndLockSystem();
QString path;
if (select_directory)
path = QFileDialog::getExistingDirectory(lock.getDialogParent(), title, initial_directory);
else
path = QFileDialog::getOpenFileName(lock.getDialogParent(), title, initial_directory, filters_str);
if (!path.isEmpty())
path = QDir::toNativeSeparators(path);
if (from_cpu_thread)
Host::RunOnCPUThread([callback = std::move(callback), path = path.toStdString()]() { callback(path); });
else
callback(path.toStdString());
});
}
void EmuThread::doBackgroundControllerPoll() void EmuThread::doBackgroundControllerPoll()
{ {
System::Internal::IdlePollUpdate(); System::Internal::IdlePollUpdate();

View File

@ -12,6 +12,7 @@
#include "scmversion/scmversion.h" #include "scmversion/scmversion.h"
#include "util/gpu_device.h" #include "util/gpu_device.h"
#include "util/imgui_fullscreen.h"
#include "util/imgui_manager.h" #include "util/imgui_manager.h"
#include "util/input_manager.h" #include "util/input_manager.h"
#include "util/platform_misc.h" #include "util/platform_misc.h"
@ -387,6 +388,18 @@ void Host::OnCoverDownloaderOpenRequested()
// noop // noop
} }
bool Host::ShouldPreferHostFileSelector()
{
return false;
}
void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directory, FileSelectorCallback callback,
FileSelectorFilters filters /* = FileSelectorFilters() */,
std::string_view initial_directory /* = std::string_view() */)
{
callback(std::string());
}
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(std::string_view str) std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(std::string_view str)
{ {
return std::nullopt; return std::nullopt;

View File

@ -7,6 +7,7 @@
#include "gpu_device.h" #include "gpu_device.h"
#include "image.h" #include "image.h"
#include "imgui_animated.h" #include "imgui_animated.h"
#include "imgui_manager.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/easing.h" #include "common/easing.h"
@ -2072,7 +2073,7 @@ void ImGuiFullscreen::PopulateFileSelectorItems()
if (s_file_selector_filters.empty() || if (s_file_selector_filters.empty() ||
std::none_of(s_file_selector_filters.begin(), s_file_selector_filters.end(), std::none_of(s_file_selector_filters.begin(), s_file_selector_filters.end(),
[&fd](const std::string& filter) { [&fd](const std::string& filter) {
return StringUtil::WildcardMatch(fd.FileName.c_str(), filter.c_str()); return StringUtil::WildcardMatch(fd.FileName.c_str(), filter.c_str(), false);
})) }))
{ {
continue; continue;
@ -2102,6 +2103,16 @@ bool ImGuiFullscreen::IsFileSelectorOpen()
void ImGuiFullscreen::OpenFileSelector(std::string_view title, bool select_directory, FileSelectorCallback callback, void ImGuiFullscreen::OpenFileSelector(std::string_view title, bool select_directory, FileSelectorCallback callback,
FileSelectorFilters filters, std::string initial_directory) FileSelectorFilters filters, std::string initial_directory)
{ {
if (initial_directory.empty() || !FileSystem::DirectoryExists(initial_directory.c_str()))
initial_directory = FileSystem::GetWorkingDirectory();
if (Host::ShouldPreferHostFileSelector())
{
Host::OpenHostFileSelectorAsync(ImGuiManager::StripIconCharacters(title), select_directory, std::move(callback),
std::move(filters), initial_directory);
return;
}
if (s_file_selector_open) if (s_file_selector_open)
CloseFileSelector(); CloseFileSelector();
@ -2111,8 +2122,6 @@ void ImGuiFullscreen::OpenFileSelector(std::string_view title, bool select_direc
s_file_selector_callback = std::move(callback); s_file_selector_callback = std::move(callback);
s_file_selector_filters = std::move(filters); s_file_selector_filters = std::move(filters);
if (initial_directory.empty() || !FileSystem::DirectoryExists(initial_directory.c_str()))
initial_directory = FileSystem::GetWorkingDirectory();
SetFileSelectorDirectory(std::move(initial_directory)); SetFileSelectorDirectory(std::move(initial_directory));
QueueResetFocus(); QueueResetFocus();
} }

View File

@ -314,3 +314,16 @@ void GetChoiceDialogHelpText(SmallStringBase& dest);
void GetFileSelectorHelpText(SmallStringBase& dest); void GetFileSelectorHelpText(SmallStringBase& dest);
void GetInputDialogHelpText(SmallStringBase& dest); void GetInputDialogHelpText(SmallStringBase& dest);
} // namespace ImGuiFullscreen } // namespace ImGuiFullscreen
// Host UI triggers from Big Picture mode.
namespace Host {
/// Returns true if native file dialogs should be preferred over Big Picture.
bool ShouldPreferHostFileSelector();
/// Opens a file selector dialog.
using FileSelectorCallback = std::function<void(const std::string& path)>;
using FileSelectorFilters = std::vector<std::string>;
void OpenHostFileSelectorAsync(std::string_view title, bool select_directory, FileSelectorCallback callback,
FileSelectorFilters filters = FileSelectorFilters(),
std::string_view initial_directory = std::string_view());
} // namespace Host

View File

@ -1123,3 +1123,25 @@ void ImGuiManager::SetSoftwareCursorPosition(u32 index, float pos_x, float pos_y
sc.pos.first = pos_x; sc.pos.first = pos_x;
sc.pos.second = pos_y; sc.pos.second = pos_y;
} }
std::string ImGuiManager::StripIconCharacters(std::string_view str)
{
std::string result;
result.reserve(str.length());
for (size_t offset = 0; offset < str.length();)
{
char32_t utf;
offset += StringUtil::DecodeUTF8(str, offset, &utf);
// icon if outside BMP/SMP/TIP, or inside private use area
if (utf > 0x32FFF || (utf >= 0xE000 && utf <= 0xF8FF))
continue;
StringUtil::EncodeAndAppendUTF8(result, utf);
}
StringUtil::StripWhitespace(&result);
return result;
}

View File

@ -106,6 +106,9 @@ void SetSoftwareCursorPosition(u32 index, float pos_x, float pos_y);
/// Adds software cursors to ImGui render list. /// Adds software cursors to ImGui render list.
void RenderSoftwareCursors(); void RenderSoftwareCursors();
/// Strips icon characters from a string.
std::string StripIconCharacters(std::string_view str);
} // namespace ImGuiManager } // namespace ImGuiManager
namespace Host { namespace Host {