Frontends: Add shared command line interface

Also provides batch mode and automatic fullscreen switching.

  -help: Displays this information and exits.
  -version: Displays version information and exits.
  -batch: Enables batch mode (exits after powering off)
  -fastboot: Force fast boot for provided filename
  -slowboot: Force slow boot for provided filename
  -resume: Load resume save state. If a boot filename is provided,
    that game's resume state will be loaded, otherwise the most
    recent resume save state will be loaded.
  -state <index>: Loads specified save state by index. If a boot
    filename is provided, a per-game state will be loaded, otherwise
    a global state will be loaded.
  -statefile <filename>: Loads state from the specified filename.
    No boot filename is required with this option.
  -fullscreen: Enters fullscreen mode immediately after starting.
  -nofullscreen: Prevents fullscreen mode from triggering if enabled.
  -portable: Forces "portable mode", data in same directory.
  --: Signals that no more arguments will follow and the remaining
    parameters make up the filename. Use when the filename contains
    spaces or starts with a dash.
This commit is contained in:
Connor McLaughlin
2020-04-13 22:13:46 +10:00
parent 6a03bb2d15
commit 81cf4b469f
12 changed files with 365 additions and 80 deletions

View File

@ -3,12 +3,13 @@
#include "qthostinterface.h"
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>
#include <cstdlib>
#include <memory>
static void InitLogging()
{
// set log flags
#ifdef Y_BUILD_CONFIG_DEBUG
#ifdef _DEBUG
Log::SetConsoleOutputParams(true, nullptr, LOGLEVEL_DEBUG);
Log::SetFilterLevel(LOGLEVEL_DEBUG);
#else
@ -35,18 +36,30 @@ int main(int argc, char* argv[])
#endif
std::unique_ptr<QtHostInterface> host_interface = std::make_unique<QtHostInterface>();
std::unique_ptr<SystemBootParameters> boot_params;
if (!host_interface->parseCommandLineParameters(argc, argv, &boot_params))
return EXIT_FAILURE;
if (!host_interface->Initialize())
{
host_interface->Shutdown();
QMessageBox::critical(nullptr, QObject::tr("DuckStation Error"),
QObject::tr("Failed to initialize host interface. Cannot continue."), QMessageBox::Ok);
return -1;
return EXIT_FAILURE;
}
std::unique_ptr<MainWindow> window = std::make_unique<MainWindow>(host_interface.get());
window->show();
host_interface->refreshGameList();
// if we're in batch mode, don't bother refreshing the game list as it won't be used
if (!host_interface->inBatchMode())
host_interface->refreshGameList();
if (boot_params)
{
host_interface->bootSystem(*boot_params);
boot_params.reset();
}
int result = app.exec();

View File

@ -528,6 +528,7 @@ void MainWindow::connectSignals()
connect(m_host_interface, &QtHostInterface::systemPerformanceCountersUpdated, this,
&MainWindow::onSystemPerformanceCountersUpdated);
connect(m_host_interface, &QtHostInterface::runningGameChanged, this, &MainWindow::onRunningGameChanged);
connect(m_host_interface, &QtHostInterface::exitRequested, this, &MainWindow::close);
// These need to be queued connections to stop crashing due to menus opening/closing and switching focus.
connect(m_game_list_widget, &GameListWidget::entrySelected, this, &MainWindow::onGameListEntrySelected,

View File

@ -39,6 +39,11 @@ QtHostInterface::~QtHostInterface()
Assert(!m_display_widget);
}
const char* QtHostInterface::GetFrontendName() const
{
return "DuckStation Qt Frontend";
}
bool QtHostInterface::Initialize()
{
createThread();
@ -104,6 +109,12 @@ bool QtHostInterface::ConfirmMessage(const char* message)
return result;
}
bool QtHostInterface::parseCommandLineParameters(int argc, char* argv[],
std::unique_ptr<SystemBootParameters>* out_boot_params)
{
return CommonHostInterface::ParseCommandLineParameters(argc, argv, out_boot_params);
}
QVariant QtHostInterface::getSettingValue(const QString& name, const QVariant& default_value)
{
std::lock_guard<std::recursive_mutex> guard(m_qsettings_mutex);
@ -320,6 +331,11 @@ bool QtHostInterface::SetFullscreen(bool enabled)
return true;
}
void QtHostInterface::RequestExit()
{
emit exitRequested();
}
std::optional<CommonHostInterface::HostKeyCode> QtHostInterface::GetHostKeyCode(const std::string_view key_code) const
{
const std::optional<int> code =

View File

@ -1,7 +1,7 @@
#pragma once
#include "common/event.h"
#include "core/host_interface.h"
#include "core/system.h"
#include "common/event.h"
#include "frontend-common/common_host_interface.h"
#include <QtCore/QByteArray>
#include <QtCore/QObject>
@ -37,6 +37,8 @@ public:
explicit QtHostInterface(QObject* parent = nullptr);
~QtHostInterface();
const char* GetFrontendName() const override;
bool Initialize() override;
void Shutdown() override;
@ -44,6 +46,8 @@ public:
void ReportMessage(const char* message) override;
bool ConfirmMessage(const char* message) override;
bool parseCommandLineParameters(int argc, char* argv[], std::unique_ptr<SystemBootParameters>* out_boot_params);
/// Thread-safe QSettings access.
QVariant getSettingValue(const QString& name, const QVariant& default_value = QVariant());
void putSettingValue(const QString& name, const QVariant& value);
@ -55,6 +59,7 @@ public:
ALWAYS_INLINE const HotkeyInfoList& getHotkeyInfoList() const { return GetHotkeyInfoList(); }
ALWAYS_INLINE ControllerInterface* getControllerInterface() const { return GetControllerInterface(); }
ALWAYS_INLINE bool inBatchMode() const { return InBatchMode(); }
ALWAYS_INLINE bool isOnWorkerThread() const { return QThread::currentThread() == m_worker_thread; }
@ -84,6 +89,7 @@ Q_SIGNALS:
void systemPerformanceCountersUpdated(float speed, float fps, float vps, float avg_frame_time,
float worst_frame_time);
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
void exitRequested();
public Q_SLOTS:
void setDefaultSettings();
@ -124,6 +130,7 @@ protected:
bool IsFullscreen() const override;
bool SetFullscreen(bool enabled) override;
void RequestExit() override;
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
void OnSystemCreated() override;
@ -161,7 +168,7 @@ private:
private:
QtHostInterface* m_parent;
std::atomic_bool m_init_result{ false };
std::atomic_bool m_init_result{false};
Common::Event m_init_event;
};