/* PCSX2 - PS2 Emulator for PCs * Copyright (C) 2002-2022 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- * ation, either version 3 of the License, or (at your option) any later version. * * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with PCSX2. * If not, see . */ #include "PrecompiledHeader.h" #include #include #include "MainWindow.h" #include "EmuThread.h" #include "QtHost.h" #include "CDVD/CDVD.h" #include "Frontend/GameList.h" #include "svnrev.h" static void PrintCommandLineVersion() { std::fprintf(stderr, "PCSX2 Version %s\n", GIT_REV); std::fprintf(stderr, "https://pcsx2.net/\n"); std::fprintf(stderr, "\n"); } static void PrintCommandLineHelp(const char* progname) { PrintCommandLineVersion(); std::fprintf(stderr, "Usage: %s [parameters] [--] [boot filename]\n", progname); std::fprintf(stderr, "\n"); std::fprintf(stderr, " -help: Displays this information and exits.\n"); std::fprintf(stderr, " -version: Displays version information and exits.\n"); std::fprintf(stderr, " -batch: Enables batch mode (exits after powering off).\n"); std::fprintf(stderr, " -fastboot: Force fast boot for provided filename.\n"); std::fprintf(stderr, " -slowboot: Force slow boot for provided filename.\n"); std::fprintf(stderr, " -resume: Load resume save state. If a boot filename is provided,\n" " that game's resume state will be loaded, otherwise the most\n" " recent resume save state will be loaded.\n"); std::fprintf(stderr, " -state : Loads specified save state by index.\n"); std::fprintf(stderr, " -statefile : Loads state from the specified filename.\n" " No boot filename is required with this option.\n"); std::fprintf(stderr, " -fullscreen: Enters fullscreen mode immediately after starting.\n"); std::fprintf(stderr, " -nofullscreen: Prevents fullscreen mode from triggering if enabled.\n"); std::fprintf(stderr, " -portable: Forces \"portable mode\", data in same directory.\n"); std::fprintf(stderr, " -settings : Loads a custom settings configuration from the\n" " specified filename. Default settings applied if file not found.\n"); std::fprintf(stderr, " --: Signals that no more arguments will follow and the remaining\n" " parameters make up the filename. Use when the filename contains\n" " spaces or starts with a dash.\n"); std::fprintf(stderr, "\n"); } static std::shared_ptr& AutoBoot(std::shared_ptr& autoboot) { if (!autoboot) { autoboot = std::make_shared(); autoboot->source_type = CDVD_SourceType::NoDisc; } return autoboot; } static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr& autoboot) { std::optional fast_boot; std::optional start_fullscreen; std::optional state_index; std::string state_filename; bool no_more_args = false; for (int i = 1; i < argc; i++) { if (!no_more_args) { #define CHECK_ARG(str) !std::strcmp(argv[i], str) #define CHECK_ARG_PARAM(str) (!std::strcmp(argv[i], str) && ((i + 1) < argc)) if (CHECK_ARG("-help")) { PrintCommandLineHelp(argv[0]); return false; } else if (CHECK_ARG("-version")) { PrintCommandLineVersion(); return false; } else if (CHECK_ARG("-batch")) { Console.WriteLn("Enabling batch mode."); AutoBoot(autoboot)->batch_mode = true; continue; } else if (CHECK_ARG("-fastboot")) { Console.WriteLn("Forcing fast boot."); fast_boot = true; continue; } else if (CHECK_ARG("-slowboot")) { Console.WriteLn("Forcing slow boot."); fast_boot = false; continue; } else if (CHECK_ARG("-resume")) { state_index = -1; continue; } else if (CHECK_ARG_PARAM("-state")) { state_index = std::atoi(argv[++i]); continue; } else if (CHECK_ARG_PARAM("-statefile")) { AutoBoot(autoboot)->save_state = argv[++i]; continue; } else if (CHECK_ARG_PARAM("-elf")) { AutoBoot(autoboot)->elf_override = argv[++i]; continue; } else if (CHECK_ARG("-fullscreen")) { Console.WriteLn("Going fullscreen after booting."); start_fullscreen = true; continue; } else if (CHECK_ARG("-nofullscreen")) { Console.WriteLn("Preventing fullscreen after booting."); start_fullscreen = false; continue; } else if (CHECK_ARG("-portable")) { Console.WriteLn("Using portable mode."); // SetUserDirectoryToProgramDirectory(); continue; } else if (CHECK_ARG("-resume")) { state_index = -1; continue; } else if (CHECK_ARG("--")) { no_more_args = true; continue; } else if (argv[i][0] == '-') { Console.Error("Unknown parameter: '%s'", argv[i]); return false; } #undef CHECK_ARG #undef CHECK_ARG_PARAM } if (!AutoBoot(autoboot)->source.empty()) AutoBoot(autoboot)->source += ' '; else AutoBoot(autoboot)->source_type = CDVD_SourceType::Iso; AutoBoot(autoboot)->source += argv[i]; } return true; } int main(int argc, char* argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); #endif #endif QApplication app(argc, argv); std::shared_ptr autoboot; if (!ParseCommandLineOptions(argc, argv, autoboot)) return EXIT_FAILURE; MainWindow* main_window = new MainWindow(QApplication::style()->objectName()); if (!QtHost::Initialize()) { delete main_window; return EXIT_FAILURE; } main_window->initialize(); EmuThread::start(); main_window->refreshGameList(false); main_window->show(); if (autoboot) g_emu_thread->startVM(std::move(autoboot)); const int result = app.exec(); EmuThread::stop(); QtHost::Shutdown(); return result; } #ifdef _WIN32 // Apparently Qt6 got rid of this? #include "common/RedtapeWindows.h" #include /* WinMain() - Initializes Windows and calls user's startup function main(). NOTE: WinMain() won't be called if the application was linked as a "console" application. */ // Convert a wchar_t to char string, equivalent to QString::toLocal8Bit() // when passed CP_ACP. static inline char* wideToMulti(unsigned int codePage, const wchar_t* aw) { const int required = WideCharToMultiByte(codePage, 0, aw, -1, nullptr, 0, nullptr, nullptr); char* result = new char[required]; WideCharToMultiByte(codePage, 0, aw, -1, result, required, nullptr, nullptr); return result; } extern "C" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR /*cmdParamarg*/, int /* cmdShow */) { int argc = 0; wchar_t** argvW = CommandLineToArgvW(GetCommandLineW(), &argc); if (argvW == nullptr) return -1; char** argv = new char*[argc + 1]; for (int i = 0; i != argc; ++i) argv[i] = wideToMulti(CP_ACP, argvW[i]); argv[argc] = nullptr; LocalFree(argvW); const int exitCode = main(argc, argv); for (int i = 0; (i != argc) && (argv[i] != nullptr); ++i) delete[] argv[i]; delete[] argv; return exitCode; } #endif