diff --git a/src/common/settings.h b/src/common/settings.h index 4eea9cf265..2dbc483950 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -622,6 +622,10 @@ struct Values { // Linux SwitchableSetting enable_gamemode{linkage, true, "enable_gamemode", Category::Linux}; +#ifdef __unix__ + SwitchableSetting gui_force_x11{linkage, false, "gui_force_x11", Category::Linux}; + Setting gui_hide_backend_warning{linkage, false, "gui_hide_backend_warning", Category::Linux}; +#endif // Controls InputSetting> players; diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index e80fde24e0..62fd81daa7 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -29,6 +29,10 @@ add_library(qt_common STATIC discord/discord.h ) +if (UNIX) + target_sources(qt_common PRIVATE gui_settings.cpp gui_settings.h) +endif() + create_target_directory_groups(qt_common) if (USE_DISCORD_PRESENCE) diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index 1957614208..67b6fb2510 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -424,6 +424,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) // Linux INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString()); +#ifdef __unix__ + INSERT(Settings, gui_force_x11, tr("Force X11 as Graphics Backend"), QString()); + INSERT(Settings, gui_hide_backend_warning, QString(), QString()); +#endif // Ui Debugging diff --git a/src/qt_common/gui_settings.cpp b/src/qt_common/gui_settings.cpp new file mode 100644 index 0000000000..982d28bbcb --- /dev/null +++ b/src/qt_common/gui_settings.cpp @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "gui_settings.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +namespace FS = Common::FS; + +namespace GraphicsBackend { + +QString GuiConfigPath() { + return QString::fromStdString(FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "gui_config.ini")); +} + +void SetForceX11(bool state) { + (void)FS::CreateParentDir(GuiConfigPath().toStdString()); + QSettings(GuiConfigPath(), QSettings::IniFormat).setValue("gui_force_x11", state); +} + +bool GetForceX11() { + return QSettings(GuiConfigPath(), QSettings::IniFormat).value("gui_force_x11", false).toBool(); +} + +} // namespace GraphicsBackend diff --git a/src/qt_common/gui_settings.h b/src/qt_common/gui_settings.h new file mode 100644 index 0000000000..d7d471d9ab --- /dev/null +++ b/src/qt_common/gui_settings.h @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +namespace GraphicsBackend { + +QString GuiConfigPath(); +void SetForceX11(bool state); +bool GetForceX11(); + +} // namespace GraphicsBackend diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4478734547..61b688374e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -23,6 +23,7 @@ #ifdef __unix__ #include #include +#include "qt_common/gui_settings.h" #endif #ifdef __linux__ #include "common/linux/gamemode.h" @@ -548,6 +549,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) // Gen keys if necessary OnCheckFirmwareDecryption(); +#ifdef __unix__ + OnCheckGraphicsBackend(); +#endif + // Check for orphaned profiles and reset profile data if necessary QtCommon::Content::FixProfiles(); @@ -3453,6 +3458,9 @@ void GMainWindow::OnConfigure() { #ifdef __linux__ const bool old_gamemode = Settings::values.enable_gamemode.GetValue(); #endif +#ifdef __unix__ + const bool old_force_x11 = Settings::values.gui_force_x11.GetValue(); +#endif Settings::SetConfiguringGlobal(true); ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), @@ -3517,6 +3525,11 @@ void GMainWindow::OnConfigure() { SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue()); } #endif +#ifdef __unix__ + if (Settings::values.gui_force_x11.GetValue() != old_force_x11) { + GraphicsBackend::SetForceX11(Settings::values.gui_force_x11.GetValue()); + } +#endif if (!multiplayer_state->IsHostingPublicRoom()) { multiplayer_state->UpdateCredentials(); @@ -4492,6 +4505,55 @@ void GMainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } +#ifdef __unix__ +void GMainWindow::OnCheckGraphicsBackend() { + const QString platformName = QGuiApplication::platformName(); + const QByteArray qtPlatform = qgetenv("QT_QPA_PLATFORM"); + + if (platformName == QStringLiteral("xcb") || qtPlatform == "xcb") + return; + + const bool isWayland = platformName.startsWith(QStringLiteral("wayland"), Qt::CaseInsensitive) || qtPlatform.startsWith("wayland"); + if (!isWayland) + return; + + const bool currently_hidden = Settings::values.gui_hide_backend_warning.GetValue(); + if (currently_hidden) + return; + + QMessageBox msgbox(this); + msgbox.setWindowTitle(tr("Wayland Detected!")); + msgbox.setText(tr("You are running Eden under Wayland Graphics Backend.\n\n" + "It's recommended to use X11 for the best compatibility.\n\n" + "There's no plan to support Wayland at moment\n" + "Expect slow performance and crashes!")); + msgbox.setIcon(QMessageBox::Warning); + + QPushButton* okButton = msgbox.addButton(tr("Use X11"), QMessageBox::AcceptRole); + QPushButton* cancelButton = msgbox.addButton(tr("Continue with Wayland"), QMessageBox::RejectRole); + msgbox.setDefaultButton(okButton); + + QCheckBox* cb = new QCheckBox(tr("Don't show again"), &msgbox); + cb->setChecked(currently_hidden); + msgbox.setCheckBox(cb); + + msgbox.exec(); + + const bool hide = cb->isChecked(); + if (hide != currently_hidden) { + Settings::values.gui_hide_backend_warning.SetValue(hide); + } + + if (msgbox.clickedButton() == okButton) { + Settings::values.gui_force_x11.SetValue(true); + GraphicsBackend::SetForceX11(true); + QMessageBox::information(this, + tr("Restart Required"), + tr("Restart Eden to apply the X11 backend.")); + } +} +#endif + bool GMainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } @@ -4985,6 +5047,9 @@ int main(int argc, char* argv[]) { qputenv("DISPLAY", ":0"); } + if (GraphicsBackend::GetForceX11()) + qputenv("QT_QPA_PLATFORM", "xcb"); + // Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop // suffix. QGuiApplication::setDesktopFileName(QStringLiteral("dev.eden_emu.eden")); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 1c2035fbab..ef8e59062e 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -413,6 +413,9 @@ private slots: void OnCreateHomeMenuApplicationMenuShortcut(); void OnCaptureScreenshot(); void OnCheckFirmwareDecryption(); +#ifdef __unix__ + void OnCheckGraphicsBackend(); +#endif void OnLanguageChanged(const QString& locale); void OnMouseActivity(); bool OnShutdownBegin();