2026-01-28 21:18:12 +01:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
2025-03-31 18:33:05 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2015-01-04 09:36:57 -08:00
|
|
|
|
2025-11-09 18:07:38 +01:00
|
|
|
#include <QApplication>
|
|
|
|
|
#include "startup_checks.h"
|
2025-07-14 01:29:57 +02:00
|
|
|
|
2025-11-09 18:07:38 +01:00
|
|
|
#if YUZU_ROOM
|
2025-05-19 21:30:10 +00:00
|
|
|
#include "dedicated_room/yuzu_room.h"
|
2025-11-09 18:07:38 +01:00
|
|
|
#include <cstring>
|
2025-05-19 21:30:10 +00:00
|
|
|
#endif
|
|
|
|
|
|
2025-11-11 07:44:14 +01:00
|
|
|
#include <common/detached_tasks.h>
|
|
|
|
|
|
2025-11-09 18:07:38 +01:00
|
|
|
#ifdef __unix__
|
|
|
|
|
#include "qt_common/gui_settings.h"
|
2018-04-19 20:22:26 +02:00
|
|
|
#endif
|
|
|
|
|
|
2025-11-09 18:07:38 +01:00
|
|
|
#include "main_window.h"
|
2022-06-10 20:37:47 -07:00
|
|
|
|
2022-05-20 19:39:12 -07:00
|
|
|
#ifdef _WIN32
|
2025-11-09 18:07:38 +01:00
|
|
|
#include <QScreen>
|
2022-05-20 19:39:12 -07:00
|
|
|
|
2022-10-01 15:27:23 -07:00
|
|
|
static void OverrideWindowsFont() {
|
2023-03-11 22:10:38 -05:00
|
|
|
// Qt5 chooses these fonts on Windows and they have fairly ugly alphanumeric/cyrillic characters
|
2022-10-01 15:27:23 -07:00
|
|
|
// Asking to use "MS Shell Dlg 2" gives better other chars while leaving the Chinese Characters.
|
|
|
|
|
const QString startup_font = QApplication::font().family();
|
|
|
|
|
const QStringList ugly_fonts = {QStringLiteral("SimSun"), QStringLiteral("PMingLiU")};
|
|
|
|
|
if (ugly_fonts.contains(startup_font)) {
|
|
|
|
|
QApplication::setFont(QFont(QStringLiteral("MS Shell Dlg 2"), 9, QFont::Normal));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-01-28 21:18:12 +01:00
|
|
|
static Qt::HighDpiScaleFactorRoundingPolicy GetHighDpiRoundingPolicy() {
|
2023-01-25 21:16:04 -05:00
|
|
|
#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.
|
|
|
|
|
|
2023-01-25 21:16:04 -05:00
|
|
|
// 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) {
|
2026-01-28 21:18:12 +01:00
|
|
|
return Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
|
2023-01-25 21:16:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QRect screen_rect = primary_screen->geometry();
|
2026-01-28 21:18:12 +01:00
|
|
|
const qreal real_ratio = primary_screen->devicePixelRatio();
|
|
|
|
|
const qreal real_width = std::trunc(screen_rect.width() * real_ratio);
|
|
|
|
|
const qreal real_height = std::trunc(screen_rect.height() * real_ratio);
|
2023-01-25 21:16:04 -05:00
|
|
|
|
|
|
|
|
// Recommended minimum width and height for proper window fit.
|
|
|
|
|
// Any screen with a lower resolution than this will still have a scale of 1.
|
2026-01-28 21:18:12 +01:00
|
|
|
constexpr qreal minimum_width = 1350.0;
|
|
|
|
|
constexpr qreal minimum_height = 900.0;
|
2023-01-25 21:16:04 -05:00
|
|
|
|
2026-01-28 21:18:12 +01:00
|
|
|
const qreal width_ratio = std::max(1.0, real_width / minimum_width);
|
|
|
|
|
const qreal height_ratio = std::max(1.0, real_height / minimum_height);
|
2023-01-25 21:16:04 -05:00
|
|
|
|
|
|
|
|
// Get the lower of the 2 ratios and truncate, this is the maximum integer scale.
|
2026-01-28 21:18:12 +01:00
|
|
|
const qreal max_ratio = std::trunc(std::min(width_ratio, height_ratio));
|
|
|
|
|
return max_ratio > real_ratio
|
|
|
|
|
? Qt::HighDpiScaleFactorRoundingPolicy::Round
|
|
|
|
|
: Qt::HighDpiScaleFactorRoundingPolicy::Floor;
|
2023-01-25 21:16:04 -05:00
|
|
|
#else
|
|
|
|
|
// Other OSes should be better than Windows at fractional scaling.
|
2026-01-28 21:18:12 +01:00
|
|
|
return Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
|
2023-01-25 21:16:04 -05:00
|
|
|
#endif
|
2023-01-25 21:16:04 -05:00
|
|
|
}
|
|
|
|
|
|
2015-07-28 18:43:18 +02:00
|
|
|
int main(int argc, char* argv[]) {
|
2025-05-19 21:30:10 +00:00
|
|
|
#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
|
|
|
|
|
|
2022-07-10 16:10:35 -04:00
|
|
|
bool has_broken_vulkan = false;
|
2022-07-10 11:29:10 -04:00
|
|
|
bool is_child = false;
|
|
|
|
|
if (CheckEnvVars(&is_child)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-19 14:46:12 -04:00
|
|
|
if (StartupChecks(argv[0], &has_broken_vulkan,
|
|
|
|
|
Settings::values.perform_vulkan_check.GetValue())) {
|
2022-07-10 14:08:20 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-04 13:11:05 -04:00
|
|
|
#ifdef YUZU_CRASH_DUMPS
|
|
|
|
|
Breakpad::InstallCrashHandler();
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-09-16 20:05:51 +02:00
|
|
|
Common::DetachedTasks detached_tasks;
|
2021-01-20 20:09:57 -03:00
|
|
|
|
2015-07-26 17:13:02 +02:00
|
|
|
// Init settings params
|
2025-05-08 22:16:07 +00:00
|
|
|
QCoreApplication::setOrganizationName(QStringLiteral("eden"));
|
2025-04-01 18:37:54 +02:00
|
|
|
QCoreApplication::setApplicationName(QStringLiteral("eden"));
|
2015-07-26 17:13:02 +02:00
|
|
|
|
2021-05-25 19:32:56 -04:00
|
|
|
#ifdef _WIN32
|
2022-01-09 14:34:46 -05:00
|
|
|
// Increases the maximum open file limit to 8192
|
|
|
|
|
_setmaxstdio(8192);
|
2025-08-30 23:08:04 +02:00
|
|
|
#elif defined(__APPLE__)
|
2019-09-05 03:40:49 +02:00
|
|
|
// If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
|
2020-07-10 13:36:38 +10:00
|
|
|
// 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
|
2021-05-25 19:32:56 -04:00
|
|
|
const auto bin_path = Common::FS::GetBundleDirectory() / "..";
|
|
|
|
|
chdir(Common::FS::PathToUTF8String(bin_path).c_str());
|
2025-12-07 07:13:43 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __unix__
|
2021-03-07 15:56:22 +00:00
|
|
|
// 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");
|
|
|
|
|
}
|
2023-12-29 17:19:48 -06:00
|
|
|
|
2025-10-29 13:16:57 +01:00
|
|
|
if (GraphicsBackend::GetForceX11() && qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM"))
|
|
|
|
|
qputenv("QT_QPA_PLATFORM", "xcb");
|
|
|
|
|
|
2023-12-29 17:19:48 -06:00
|
|
|
// Fix the Wayland appId. This needs to match the name of the .desktop file without the .desktop
|
|
|
|
|
// suffix.
|
2025-08-31 04:56:23 +02:00
|
|
|
QGuiApplication::setDesktopFileName(QStringLiteral("dev.eden_emu.eden"));
|
2021-03-07 15:56:22 +00:00
|
|
|
#endif
|
|
|
|
|
|
2026-01-28 21:18:12 +01:00
|
|
|
auto rounding_policy = GetHighDpiRoundingPolicy();
|
|
|
|
|
QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy);
|
2023-01-25 21:16:04 -05:00
|
|
|
|
2023-01-25 18:45:22 -05:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
|
|
|
// Disables the "?" button on all dialogs. Disabled by default on Qt6.
|
2023-01-25 01:11:20 -05:00
|
|
|
QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
2023-01-25 18:45:22 -05:00
|
|
|
#endif
|
2023-01-25 01:11:20 -05:00
|
|
|
|
2019-01-11 21:06:34 -07:00
|
|
|
// Enables the core to make the qt created contexts current on std::threads
|
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
2023-01-25 21:16:04 -05:00
|
|
|
|
2025-07-30 21:00:54 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
QApplication::setStyle(QStringLiteral("windowsvista"));
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-03-31 22:26:50 -04:00
|
|
|
QApplication app(argc, argv);
|
2014-12-06 20:00:08 -02:00
|
|
|
|
2022-10-01 15:27:23 -07:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
OverrideWindowsFont();
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-08-03 17:31:57 -07:00
|
|
|
// 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
|
2022-08-31 03:10:34 -07:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
2022-08-03 17:31:57 -07:00
|
|
|
const QLocale locale = QLocale::system();
|
|
|
|
|
if (QStringLiteral("\u3008") == locale.toString(1)) {
|
|
|
|
|
QLocale::setDefault(QLocale::system().name());
|
|
|
|
|
}
|
2022-08-31 03:10:34 -07:00
|
|
|
#endif
|
2022-08-03 17:31:57 -07:00
|
|
|
|
2016-09-18 09:38:01 +09:00
|
|
|
// Qt changes the locale and causes issues in float conversion using std::to_string() when
|
|
|
|
|
// generating shaders
|
2016-03-06 14:04:47 +01:00
|
|
|
setlocale(LC_ALL, "C");
|
|
|
|
|
|
2025-11-09 18:07:38 +01:00
|
|
|
MainWindow main_window{has_broken_vulkan};
|
2014-12-06 20:00:08 -02:00
|
|
|
// After settings have been loaded by GMainWindow, apply the filter
|
2014-03-31 22:26:50 -04:00
|
|
|
main_window.show();
|
2018-07-10 18:02:14 +08:00
|
|
|
|
2025-08-15 04:12:45 +02:00
|
|
|
app.connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
|
2025-11-09 18:07:38 +01:00
|
|
|
&MainWindow::OnAppFocusStateChanged);
|
2019-09-26 14:54:31 +02:00
|
|
|
|
2018-09-16 20:05:51 +02:00
|
|
|
int result = app.exec();
|
|
|
|
|
detached_tasks.WaitForAllTasks();
|
|
|
|
|
return result;
|
2014-03-31 22:26:50 -04:00
|
|
|
}
|