Duckstation/src/duckstation-qt/qthostinterface.h

217 lines
6.9 KiB
C
Raw Normal View History

2019-12-31 06:17:17 +00:00
#pragma once
#include "common/event.h"
2019-12-31 06:17:17 +00:00
#include "core/host_interface.h"
#include "core/system.h"
#include "frontend-common/common_host_interface.h"
2020-01-07 08:55:36 +00:00
#include <QtCore/QByteArray>
#include <QtCore/QObject>
#include <QtCore/QSettings>
#include <QtCore/QThread>
#include <atomic>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
2020-01-05 02:46:03 +00:00
#include <utility>
2020-01-07 08:55:36 +00:00
#include <vector>
class ByteStream;
2019-12-31 06:17:17 +00:00
class QEventLoop;
2020-02-15 15:14:04 +00:00
class QMenu;
2019-12-31 06:17:17 +00:00
class QWidget;
class QTimer;
2019-12-31 06:17:17 +00:00
class GameList;
class MainWindow;
class QtHostDisplay;
Q_DECLARE_METATYPE(SystemBootParameters);
class QtHostInterface final : public QObject, private CommonHostInterface
2019-12-31 06:17:17 +00:00
{
Q_OBJECT
public:
explicit QtHostInterface(QObject* parent = nullptr);
~QtHostInterface();
const char* GetFrontendName() const override;
bool Initialize() override;
void Shutdown() override;
2019-12-31 06:17:17 +00:00
void ReportError(const char* message) override;
void ReportMessage(const char* message) override;
bool ConfirmMessage(const char* message) override;
2019-12-31 06:17:17 +00:00
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);
void removeSettingValue(const QString& name);
2019-12-31 06:17:17 +00:00
ALWAYS_INLINE const GameList* getGameList() const { return m_game_list.get(); }
ALWAYS_INLINE GameList* getGameList() { return m_game_list.get(); }
2020-01-08 03:37:43 +00:00
void refreshGameList(bool invalidate_cache = false, bool invalidate_database = false);
2019-12-31 06:17:17 +00:00
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; }
2019-12-31 06:17:17 +00:00
ALWAYS_INLINE MainWindow* getMainWindow() const { return m_main_window; }
void setMainWindow(MainWindow* window);
QtHostDisplay* createHostDisplay();
2019-12-31 06:17:17 +00:00
2020-02-15 15:14:04 +00:00
void populateSaveStateMenus(const char* game_code, QMenu* load_menu, QMenu* save_menu);
/// Fills menu with save state info and handlers.
void populateGameListContextMenu(const char* game_code, QWidget* parent_window, QMenu* menu);
ALWAYS_INLINE QString getPathForInputProfile(const QString& name) const
{
return QString::fromStdString(GetPathForInputProfile(name.toUtf8().constData()));
}
2020-04-14 15:44:16 +00:00
ALWAYS_INLINE std::vector<std::pair<std::string, std::string>> getInputProfileList() const
{
return GetInputProfileList();
}
void saveInputProfile(const QString& profile_path);
2019-12-31 06:17:17 +00:00
Q_SIGNALS:
void errorReported(const QString& message);
void messageReported(const QString& message);
bool messageConfirmed(const QString& message);
2019-12-31 06:17:17 +00:00
void emulationStarted();
void emulationStopped();
void emulationPaused(bool paused);
void stateSaved(const QString& game_code, bool global, qint32 slot);
2019-12-31 06:17:17 +00:00
void gameListRefreshed();
void createDisplayRequested(QThread* worker_thread, bool use_debug_device, bool fullscreen, bool render_to_main);
void updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
void focusDisplayWidgetRequested();
void destroyDisplayRequested();
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();
2020-04-14 15:44:16 +00:00
void inputProfileLoaded();
2019-12-31 06:17:17 +00:00
public Q_SLOTS:
void setDefaultSettings();
void applySettings();
void updateInputMap();
2020-04-14 15:44:16 +00:00
void applyInputProfile(const QString& profile_path);
void onDisplayWindowKeyEvent(int key, bool pressed);
2020-04-26 07:36:49 +00:00
void onDisplayWindowMouseMoveEvent(int x, int y);
void onDisplayWindowMouseButtonEvent(int button, bool pressed);
void bootSystem(const SystemBootParameters& params);
void resumeSystemFromState(const QString& filename, bool boot_on_failure);
void powerOffSystem();
void synchronousPowerOffSystem();
2019-12-31 06:17:17 +00:00
void resetSystem();
void pauseSystem(bool paused);
void changeDisc(const QString& new_disc_filename);
void loadState(const QString& filename);
2020-02-15 15:14:04 +00:00
void loadState(bool global, qint32 slot);
void saveState(bool global, qint32 slot, bool block_until_done = false);
2020-03-15 12:04:32 +00:00
void startDumpingAudio();
void stopDumpingAudio();
2020-03-15 14:06:39 +00:00
void saveScreenshot();
void redrawDisplayWindow();
void toggleFullscreen();
2019-12-31 06:17:17 +00:00
private Q_SLOTS:
void doStopThread();
void onHostDisplayWindowResized(int width, int height);
void doBackgroundControllerPoll();
2019-12-31 06:17:17 +00:00
protected:
bool AcquireHostDisplay() override;
void ReleaseHostDisplay() override;
bool IsFullscreen() const override;
bool SetFullscreen(bool enabled) override;
void PollAndUpdate() override;
void RequestExit() override;
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
void OnSystemCreated() override;
void OnSystemPaused(bool paused) override;
void OnSystemDestroyed() override;
void OnSystemPerformanceCountersUpdated() override;
void OnRunningGameChanged() override;
void OnSystemStateSaved(bool global, s32 slot) override;
void LoadSettings() override;
void SetDefaultSettings(SettingsInterface& si) override;
void ApplySettings(SettingsInterface& si) override;
void UpdateInputMap() override;
2019-12-31 06:17:17 +00:00
private:
enum : u32
{
BACKGROUND_CONTROLLER_POLLING_INTERVAL =
100 /// Interval at which the controllers are polled when the system is not active.
};
2020-01-05 02:46:03 +00:00
using InputButtonHandler = std::function<void(bool)>;
2020-02-17 15:06:28 +00:00
using InputAxisHandler = std::function<void(float)>;
2020-01-05 02:46:03 +00:00
2019-12-31 06:17:17 +00:00
class Thread : public QThread
{
public:
Thread(QtHostInterface* parent);
~Thread();
void setInitResult(bool result);
bool waitForInit();
2019-12-31 06:17:17 +00:00
protected:
void run() override;
private:
QtHostInterface* m_parent;
std::atomic_bool m_init_result{false};
Common::Event m_init_event;
2019-12-31 06:17:17 +00:00
};
QtHostDisplay* getHostDisplay();
void createBackgroundControllerPollTimer();
void destroyBackgroundControllerPollTimer();
void startBackgroundControllerPollTimer();
void stopBackgroundControllerPollTimer();
2019-12-31 06:17:17 +00:00
void createThread();
void stopThread();
void threadEntryPoint();
bool initializeOnThread();
void shutdownOnThread();
void renderDisplay();
void connectDisplaySignals();
void disconnectDisplaySignals();
void updateDisplayState();
void wakeThread();
2019-12-31 06:17:17 +00:00
std::unique_ptr<QSettings> m_qsettings;
std::recursive_mutex m_qsettings_mutex;
2019-12-31 06:17:17 +00:00
MainWindow* m_main_window = nullptr;
2019-12-31 06:17:17 +00:00
QThread* m_original_thread = nullptr;
Thread* m_worker_thread = nullptr;
QEventLoop* m_worker_thread_event_loop = nullptr;
2019-12-31 06:17:17 +00:00
std::atomic_bool m_shutdown_flag{false};
2019-12-31 06:17:17 +00:00
QTimer* m_background_controller_polling_timer = nullptr;
bool m_is_rendering_to_main = false;
bool m_is_fullscreen = false;
};