// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include #include "startup_checks.h" #if YUZU_ROOM #include "dedicated_room/yuzu_room.h" #include #include #endif #ifdef __unix__ #include "qt_common/gui_settings.h" #endif #include "main_window.h" static void SetHighDPIAttributes() { #ifdef _WIN32 // For Windows, we want to avoid scaling artifacts on fractional scaling ratios. // This is done by setting the optimal scaling policy for the primary screen. // Create a temporary QApplication. int temp_argc = 0; char** temp_argv = nullptr; QApplication temp{temp_argc, temp_argv}; // Get the current screen geometry. const QScreen* primary_screen = QGuiApplication::primaryScreen(); if (primary_screen == nullptr) { return; } const QRect screen_rect = primary_screen->geometry(); const int real_width = screen_rect.width(); const int real_height = screen_rect.height(); const float real_ratio = primary_screen->logicalDotsPerInch() / 96.0f; // Recommended minimum width and height for proper window fit. // Any screen with a lower resolution than this will still have a scale of 1. constexpr float minimum_width = 1350.0f; constexpr float minimum_height = 900.0f; const float width_ratio = (std::max)(1.0f, real_width / minimum_width); const float height_ratio = (std::max)(1.0f, real_height / minimum_height); // Get the lower of the 2 ratios and truncate, this is the maximum integer scale. const float max_ratio = std::trunc((std::min)(width_ratio, height_ratio)); if (max_ratio > real_ratio) { QApplication::setHighDpiScaleFactorRoundingPolicy( Qt::HighDpiScaleFactorRoundingPolicy::Round); } else { QApplication::setHighDpiScaleFactorRoundingPolicy( Qt::HighDpiScaleFactorRoundingPolicy::Floor); } #else // Other OSes should be better than Windows at fractional scaling. QApplication::setHighDpiScaleFactorRoundingPolicy( Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif } int main(int argc, char* argv[]) { #if YUZU_ROOM bool launch_room = false; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--room") == 0) { launch_room = true; } } if (launch_room) { LaunchRoom(argc, argv, true); return 0; } #endif bool has_broken_vulkan = false; bool is_child = false; if (CheckEnvVars(&is_child)) { return 0; } if (StartupChecks(argv[0], &has_broken_vulkan, Settings::values.perform_vulkan_check.GetValue())) { return 0; } #ifdef YUZU_CRASH_DUMPS Breakpad::InstallCrashHandler(); #endif Common::DetachedTasks detached_tasks; // Init settings params QCoreApplication::setOrganizationName(QStringLiteral("eden")); QCoreApplication::setApplicationName(QStringLiteral("eden")); #ifdef _WIN32 // Increases the maximum open file limit to 8192 _setmaxstdio(8192); #elif defined(__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()); #elif defined(__unix__) && !defined(__ANDROID__) // 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"); } if (GraphicsBackend::GetForceX11() && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) 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")); #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); #ifdef _WIN32 QApplication::setStyle(QStringLiteral("windowsvista")); #endif QApplication app(argc, argv); #ifdef _WIN32 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 // This bug is fixed in Qt6, specifically 6.0.0-alpha1 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const QLocale locale = QLocale::system(); if (QStringLiteral("\u3008") == locale.toString(1)) { QLocale::setDefault(QLocale::system().name()); } #endif // Qt changes the locale and causes issues in float conversion using std::to_string() when // generating shaders setlocale(LC_ALL, "C"); MainWindow main_window{has_broken_vulkan}; // After settings have been loaded by GMainWindow, apply the filter main_window.show(); app.connect(&app, &QGuiApplication::applicationStateChanged, &main_window, &MainWindow::OnAppFocusStateChanged); int result = app.exec(); detached_tasks.WaitForAllTasks(); return result; }