fix(overhaul): UI and resolution bugs for Steam Deck (Gamescope)

Signed-off-by: Collecting <collecting@noreply.localhost>
This commit is contained in:
Collecting
2026-01-04 02:15:08 +00:00
parent f5b9abc77c
commit 84c7739444

View File

@@ -1159,9 +1159,6 @@ void GMainWindow::InitializeWidgets() {
multiplayer_room_overlay = new MultiplayerRoomOverlay(this);
multiplayer_room_overlay->hide();
connect(this, &GMainWindow::EmulationStarting, multiplayer_room_overlay, &MultiplayerRoomOverlay::OnEmulationStarting);
connect(this, &GMainWindow::EmulationStopping, multiplayer_room_overlay, &MultiplayerRoomOverlay::OnEmulationStopping);
vram_overlay = new VramOverlay(this);
vram_overlay->hide();
@@ -1353,6 +1350,25 @@ void GMainWindow::InitializeWidgets() {
statusBar()->setVisible(true);
setStyleSheet(QStringLiteral("QStatusBar::item{border: none;}"));
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
if (is_gamescope) {
statusBar()->setSizeGripEnabled(true);
this->menuBar()->setNativeMenuBar(false);
this->setContentsMargins(0, 0, 0, 0);
this->layout()->setContentsMargins(0, 0, 0, 0);
this->layout()->setSpacing(0);
ui->horizontalLayout->setContentsMargins(0, 0, 0, 0);
ui->horizontalLayout->setSpacing(0);
statusBar()->setStyleSheet(QStringLiteral(
"QStatusBar::item { border: none; }"
"QSizeGrip { width: 20px; height: 20px; margin: 2px; }"
));
}
}
void GMainWindow::InitializeDebugWidgets() {
@@ -1483,6 +1499,12 @@ void GMainWindow::InitializeHotkeys() {
}
void GMainWindow::SetDefaultUIGeometry() {
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
if (is_gamescope) {
this->resize(1280, 800);
return;
}
// geometry: 53% of the window contents are in the upper screen half, 47% in the lower half
const QRect screenRect = QGuiApplication::primaryScreen()->geometry();
@@ -1495,15 +1517,25 @@ void GMainWindow::SetDefaultUIGeometry() {
}
void GMainWindow::RestoreUIState() {
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
restoreGeometry(UISettings::values.geometry);
if (!is_gamescope) {
restoreGeometry(UISettings::values.geometry);
}
// Work-around because the games list isn't supposed to be full screen
if (isFullScreen()) {
showNormal();
}
restoreState(UISettings::values.state);
render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
if (!is_gamescope) {
render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
}
#if MICROPROFILE_ENABLED
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
microProfileDialog->setVisible(UISettings::values.microprofile_visible.GetValue());
@@ -1528,13 +1560,12 @@ void GMainWindow::RestoreUIState() {
ui->action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar.GetValue());
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
// Force the performance overlay to be off on startup
// Force overlays off on startup
ui->action_Show_Performance_Overlay->setChecked(false);
if (performance_overlay) {
performance_overlay->SetVisible(false);
}
// Force the VRAM overlay to be off on startup
ui->action_Show_Vram_Overlay->setChecked(false);
if (vram_overlay) {
vram_overlay->SetVisible(false);
@@ -4015,14 +4046,16 @@ void GMainWindow::ShowFullscreen() {
}
void GMainWindow::HideFullscreen() {
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
if (ui->action_Single_Window_Mode->isChecked()) {
if (UsingExclusiveFullscreen()) {
showNormal();
restoreGeometry(UISettings::values.geometry);
if (!is_gamescope) restoreGeometry(UISettings::values.geometry);
} else {
hide();
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
restoreGeometry(UISettings::values.geometry);
if (!is_gamescope) restoreGeometry(UISettings::values.geometry);
raise();
show();
}
@@ -4032,15 +4065,18 @@ void GMainWindow::HideFullscreen() {
} else {
if (UsingExclusiveFullscreen()) {
render_window->showNormal();
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
if (!is_gamescope) render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
} else {
render_window->hide();
render_window->setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
if (!is_gamescope) render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
render_window->raise();
render_window->show();
}
}
if (is_gamescope) {
}
}
void GMainWindow::ToggleWindowMode() {
@@ -4069,9 +4105,14 @@ void GMainWindow::ToggleWindowMode() {
}
void GMainWindow::ResetWindowSize(u32 width, u32 height) {
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
if (is_gamescope) {
return;
}
const auto aspect_ratio = Layout::EmulationAspectRatio(
static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()),
static_cast<float>(height) / width);
static_cast<float>(height) / width);
if (!ui->action_Single_Window_Mode->isChecked()) {
render_window->resize(height / aspect_ratio, height);
} else {
@@ -5564,10 +5605,14 @@ void GMainWindow::UpdateStatusButtons() {
}
void GMainWindow::UpdateUISettings() {
if (!ui->action_Fullscreen->isChecked()) {
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
// Only save/restore geometry if we are NOT in gamescope to prevent resolution bugs
if (!ui->action_Fullscreen->isChecked() && !is_gamescope) {
UISettings::values.geometry = saveGeometry();
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
}
UISettings::values.state = saveState();
#if MICROPROFILE_ENABLED
UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
@@ -6096,13 +6141,9 @@ static void SetHighDPIAttributes() {
int main(int argc, char* argv[]) {
// Set environment variables for AppImage compatibility
// This must be done before the QApplication is created.
const bool is_appimage = !qgetenv("APPIMAGE").isEmpty();
if (is_appimage) {
// Fixes Wayland crash with NVIDIA drivers by disabling explicit sync.
qputenv("QT_WAYLAND_DISABLE_EXPLICIT_SYNC", "1");
// Tell the bundled OpenSSL where to find the bundled certificates.
const QDir app_dir(QCoreApplication::applicationDirPath());
const QString certs_path = app_dir.filePath(QString::fromLatin1("../etc/ssl/certs"));
qputenv("SSL_CERT_DIR", certs_path.toUtf8());
@@ -6133,45 +6174,42 @@ int main(int argc, char* argv[]) {
Common::ConfigureNvidiaEnvironmentFlags();
// Init settings params
QCoreApplication::setOrganizationName(QStringLiteral("citron team"));
QCoreApplication::setApplicationName(QStringLiteral("citron"));
#ifdef _WIN32
// Increases the maximum open file limit to 8192
_setmaxstdio(8192);
#endif
#ifdef __APPLE__
// If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
// But since we require the working directory to be the executable path for the location of
// the user folder in the Qt Frontend, we need to cd into that working directory
const auto bin_path = Common::FS::GetBundleDirectory() / "..";
chdir(Common::FS::PathToUTF8String(bin_path).c_str());
#endif
#ifdef __linux__
// Set the DISPLAY variable in order to open web browsers
// TODO (lat9nq): Find a better solution for AppImages to start external applications
if (QString::fromLocal8Bit(qgetenv("DISPLAY")).isEmpty()) {
qputenv("DISPLAY", ":0");
}
// Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop
// suffix.
QGuiApplication::setDesktopFileName(QStringLiteral("org.citron_emu.citron"));
#endif
SetHighDPIAttributes();
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// Disables the "?" button on all dialogs. Disabled by default on Qt6.
QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
#endif
// Enables the core to make the qt created contexts current on std::threads
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
const bool is_gamescope = !qgetenv("GAMESCOPE_WIDTH").isEmpty() || qgetenv("XDG_CURRENT_DESKTOP") == "gamescope";
if (is_gamescope) {
qputenv("QT_ENABLE_HIGHDPI_SCALING", "0");
qputenv("QT_SCALE_FACTOR", "1");
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0");
qputenv("QT_FONT_DPI", "96");
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
}
QApplication app(argc, argv);
#ifdef __linux__
if (QGuiApplication::platformName().startsWith(QStringLiteral("wayland"))) {
@@ -6179,7 +6217,7 @@ int main(int argc, char* argv[]) {
}
#endif
#ifdef CITRON_USE_AUTO_UPDATER
#ifdef CITRON_USE_AUTO_UPDATER
// Check for and apply staged updates before starting the main application
std::filesystem::path app_dir = std::filesystem::path(QCoreApplication::applicationDirPath().toStdString());
@@ -6211,6 +6249,7 @@ int main(int argc, char* argv[]) {
OverrideWindowsFont();
#endif
// Workaround for QTBUG-85409, for Suzhou numerals the number 1 is actually \u3021
// so we can see if we get \u3008 instead
// TL;DR all other number formats are consecutive in unicode code points
@@ -6222,21 +6261,31 @@ int main(int argc, char* argv[]) {
}
#endif
// Qt changes the locale and causes issues in float conversion using std::to_string() when
// generating shaders
setlocale(LC_ALL, "C");
GMainWindow main_window{std::move(config), has_broken_vulkan};
app.setStyle(new RainbowStyle(app.style()));
main_window.show();
if (is_gamescope) {
QTimer::singleShot(200, &main_window, [&main_window]() {
main_window.showMaximized();
if (main_window.layout()) {
main_window.layout()->activate();
}
main_window.update();
main_window.raise();
main_window.activateWindow();
});
}
QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
&GMainWindow::OnAppFocusStateChanged);
int result = app.exec();
detached_tasks.WaitForAllTasks();
return result;
}