Qt: Fix crash on language change with system active

This commit is contained in:
Stenzek 2023-11-29 19:48:39 +10:00
parent 8ce2be57c5
commit e806d939ae
No known key found for this signature in database
4 changed files with 63 additions and 34 deletions

View file

@ -709,12 +709,14 @@ std::string MainWindow::getDeviceDiscPath(const QString& title)
void MainWindow::recreate() void MainWindow::recreate()
{ {
if (s_system_valid) const bool was_display_created = m_display_created;
if (was_display_created)
{ {
requestShutdown(false, true, true); g_emu_thread->setSurfaceless(true);
while (m_display_widget || !g_emu_thread->isSurfaceless())
while (s_system_valid)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
m_display_created = false;
} }
// We need to close input sources, because e.g. DInput uses our window handle. // We need to close input sources, because e.g. DInput uses our window handle.
@ -724,11 +726,19 @@ void MainWindow::recreate()
g_main_window = nullptr; g_main_window = nullptr;
MainWindow* new_main_window = new MainWindow(); MainWindow* new_main_window = new MainWindow();
DebugAssert(g_main_window == new_main_window);
new_main_window->show(); new_main_window->show();
deleteLater(); deleteLater();
// Reload the sources we just closed. // Reload the sources we just closed.
g_emu_thread->reloadInputSources(); g_emu_thread->reloadInputSources();
if (was_display_created)
{
g_emu_thread->setSurfaceless(false);
g_main_window->updateEmulationActions(false, System::IsValid(), Achievements::IsHardcoreModeActive());
g_main_window->onFullscreenUIStateChange(g_emu_thread->isRunningFullscreenUI());
}
} }
void MainWindow::destroySubWindows() void MainWindow::destroySubWindows()
@ -2464,9 +2474,10 @@ void MainWindow::showEvent(QShowEvent* event)
void MainWindow::closeEvent(QCloseEvent* event) void MainWindow::closeEvent(QCloseEvent* event)
{ {
// If there's no VM, we can just exit as normal. // If there's no VM, we can just exit as normal.
if (!s_system_valid) if (!s_system_valid || !m_display_created)
{ {
saveGeometryToConfig(); saveGeometryToConfig();
if (m_display_created)
g_emu_thread->stopFullscreenUI(); g_emu_thread->stopFullscreenUI();
destroySubWindows(); destroySubWindows();
QMainWindow::closeEvent(event); QMainWindow::closeEvent(event);

View file

@ -53,8 +53,6 @@ static QString FixLanguageName(const QString& language);
static std::string GetFontPath(const GlyphInfo* gi); static std::string GetFontPath(const GlyphInfo* gi);
static void UpdateGlyphRanges(const std::string_view& language); static void UpdateGlyphRanges(const std::string_view& language);
static const GlyphInfo* GetGlyphInfo(const std::string_view& language); static const GlyphInfo* GetGlyphInfo(const std::string_view& language);
static std::vector<ImWchar> s_glyph_ranges;
} // namespace QtHost } // namespace QtHost
static std::vector<QTranslator*> s_translators; static std::vector<QTranslator*> s_translators;
@ -133,9 +131,18 @@ void QtHost::InstallTranslator()
qApp->installTranslator(translator); qApp->installTranslator(translator);
s_translators.push_back(translator); s_translators.push_back(translator);
UpdateGlyphRanges(language.toStdString()); // We end up here both on language change, and on startup.
if (g_emu_thread)
{
Host::RunOnCPUThread([language = language.toStdString()]() {
UpdateGlyphRanges(language);
Host::ClearTranslationCache(); Host::ClearTranslationCache();
});
}
else
{
UpdateGlyphRanges(language.toStdString());
}
} }
QString QtHost::FixLanguageName(const QString& language) QString QtHost::FixLanguageName(const QString& language)
@ -233,10 +240,11 @@ void QtHost::UpdateGlyphRanges(const std::string_view& language)
const GlyphInfo* gi = GetGlyphInfo(language); const GlyphInfo* gi = GetGlyphInfo(language);
std::string font_path; std::string font_path;
s_glyph_ranges.clear(); std::vector<ImWchar> glyph_ranges;
glyph_ranges.clear();
// Base Latin range is always included. // Base Latin range is always included.
s_glyph_ranges.insert(s_glyph_ranges.begin(), std::begin(s_base_latin_range), std::end(s_base_latin_range)); glyph_ranges.insert(glyph_ranges.begin(), std::begin(s_base_latin_range), std::end(s_base_latin_range));
if (gi) if (gi)
{ {
@ -247,8 +255,8 @@ void QtHost::UpdateGlyphRanges(const std::string_view& language)
{ {
// Always should be in pairs. // Always should be in pairs.
DebugAssert(ptr[0] != 0 && ptr[1] != 0); DebugAssert(ptr[0] != 0 && ptr[1] != 0);
s_glyph_ranges.push_back(*(ptr++)); glyph_ranges.push_back(*(ptr++));
s_glyph_ranges.push_back(*(ptr++)); glyph_ranges.push_back(*(ptr++));
} }
} }
@ -258,16 +266,15 @@ void QtHost::UpdateGlyphRanges(const std::string_view& language)
// If we don't have any specific glyph range, assume Central European, except if English, then keep the size down. // If we don't have any specific glyph range, assume Central European, except if English, then keep the size down.
if ((!gi || !gi->used_glyphs) && language != "en") if ((!gi || !gi->used_glyphs) && language != "en")
{ {
s_glyph_ranges.insert(s_glyph_ranges.begin(), std::begin(s_central_european_ranges), glyph_ranges.insert(glyph_ranges.begin(), std::begin(s_central_european_ranges),
std::end(s_central_european_ranges)); std::end(s_central_european_ranges));
} }
// List terminator. // List terminator.
s_glyph_ranges.push_back(0); glyph_ranges.push_back(0);
s_glyph_ranges.push_back(0); glyph_ranges.push_back(0);
ImGuiManager::SetFontPath(std::move(font_path)); ImGuiManager::SetFontPathAndRange(std::move(font_path), std::move(glyph_ranges));
ImGuiManager::SetFontRange(s_glyph_ranges.data());
} }
// clang-format off // clang-format off

View file

@ -74,7 +74,7 @@ static float s_global_prescale = 1.0f; // before window scale
static float s_global_scale = 1.0f; static float s_global_scale = 1.0f;
static std::string s_font_path; static std::string s_font_path;
static const ImWchar* s_font_range = nullptr; static std::vector<ImWchar> s_font_range;
static ImFont* s_standard_font; static ImFont* s_standard_font;
static ImFont* s_fixed_font; static ImFont* s_fixed_font;
@ -109,16 +109,30 @@ static bool s_global_prescale_changed = false;
static std::array<ImGuiManager::SoftwareCursor, InputManager::MAX_SOFTWARE_CURSORS> s_software_cursors = {}; static std::array<ImGuiManager::SoftwareCursor, InputManager::MAX_SOFTWARE_CURSORS> s_software_cursors = {};
} // namespace ImGuiManager } // namespace ImGuiManager
void ImGuiManager::SetFontPath(std::string path) void ImGuiManager::SetFontPathAndRange(std::string path, std::vector<u16> range)
{ {
s_font_path = std::move(path); if (s_font_path == path && s_font_range == range)
s_standard_font_data = {}; return;
}
void ImGuiManager::SetFontRange(const u16* range) s_font_path = std::move(path);
{ s_font_range = std::move(range);
s_font_range = range;
s_standard_font_data = {}; s_standard_font_data = {};
if (ImGui::GetCurrentContext())
{
ImGui::EndFrame();
if (!LoadFontData())
Panic("Failed to load font data");
if (!AddImGuiFonts(HasFullscreenFonts()))
Panic("Failed to create ImGui font text");
if (!g_gpu_device->UpdateImGuiFontTexture())
Panic("Failed to recreate font texture after scale+resize");
NewFrame();
}
} }
void ImGuiManager::SetGlobalScale(float global_scale) void ImGuiManager::SetGlobalScale(float global_scale)
@ -527,7 +541,7 @@ ImFont* ImGuiManager::AddTextFont(float size)
cfg.FontDataOwnedByAtlas = false; cfg.FontDataOwnedByAtlas = false;
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_standard_font_data.data(), return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_standard_font_data.data(),
static_cast<int>(s_standard_font_data.size()), size, &cfg, static_cast<int>(s_standard_font_data.size()), size, &cfg,
s_font_range ? s_font_range : default_ranges); s_font_range.empty() ? default_ranges : s_font_range.data());
} }
ImFont* ImGuiManager::AddFixedFont(float size) ImFont* ImGuiManager::AddFixedFont(float size)

View file

@ -13,10 +13,7 @@ enum class GenericInputBinding : u8;
namespace ImGuiManager { namespace ImGuiManager {
/// Sets the path to the font to use. Empty string means to use the default. /// Sets the path to the font to use. Empty string means to use the default.
void SetFontPath(std::string path); void SetFontPathAndRange(std::string path, std::vector<u16> range);
/// Sets the glyph range to use when loading fonts.
void SetFontRange(const u16* range);
/// Changes the global scale. /// Changes the global scale.
void SetGlobalScale(float global_scale); void SetGlobalScale(float global_scale);