2019-12-31 06:17:17 +00:00
|
|
|
#pragma once
|
2020-04-13 12:13:46 +00:00
|
|
|
#include "common/event.h"
|
2019-12-31 06:17:17 +00:00
|
|
|
#include "core/host_interface.h"
|
2020-03-02 01:08:16 +00:00
|
|
|
#include "core/system.h"
|
2020-02-28 07:00:09 +00:00
|
|
|
#include "frontend-common/common_host_interface.h"
|
2021-02-21 06:53:14 +00:00
|
|
|
#include "qtutils.h"
|
2020-01-07 08:55:36 +00:00
|
|
|
#include <QtCore/QByteArray>
|
2020-01-02 06:13:03 +00:00
|
|
|
#include <QtCore/QObject>
|
|
|
|
#include <QtCore/QSettings>
|
2020-07-21 09:49:04 +00:00
|
|
|
#include <QtCore/QString>
|
2020-01-02 06:13:03 +00:00
|
|
|
#include <QtCore/QThread>
|
|
|
|
#include <atomic>
|
|
|
|
#include <functional>
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
2020-01-24 04:49:49 +00:00
|
|
|
#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
|
|
|
|
2020-01-10 03:28:13 +00:00
|
|
|
class QEventLoop;
|
2020-02-15 15:14:04 +00:00
|
|
|
class QMenu;
|
2019-12-31 06:17:17 +00:00
|
|
|
class QWidget;
|
2020-02-15 15:14:53 +00:00
|
|
|
class QTimer;
|
2020-07-28 09:14:44 +00:00
|
|
|
class QTranslator;
|
2019-12-31 06:17:17 +00:00
|
|
|
|
|
|
|
class GameList;
|
2020-11-10 13:24:07 +00:00
|
|
|
struct GameListEntry;
|
2020-07-13 16:24:11 +00:00
|
|
|
class INISettingsInterface;
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-03-12 05:32:30 +00:00
|
|
|
class MainWindow;
|
2020-06-29 16:46:57 +00:00
|
|
|
class QtDisplayWidget;
|
2020-03-12 03:53:51 +00:00
|
|
|
|
2020-09-12 20:01:08 +00:00
|
|
|
Q_DECLARE_METATYPE(std::shared_ptr<const SystemBootParameters>);
|
2020-03-02 01:08:16 +00:00
|
|
|
|
2020-07-13 16:24:11 +00:00
|
|
|
class QtHostInterface final : public QObject, public CommonHostInterface
|
2019-12-31 06:17:17 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit QtHostInterface(QObject* parent = nullptr);
|
|
|
|
~QtHostInterface();
|
|
|
|
|
2020-09-13 10:21:33 +00:00
|
|
|
ALWAYS_INLINE static QtHostInterface* GetInstance() { return static_cast<QtHostInterface*>(g_host_interface); }
|
|
|
|
|
2020-04-13 12:13:46 +00:00
|
|
|
const char* GetFrontendName() const override;
|
|
|
|
|
2020-03-21 14:49:46 +00:00
|
|
|
bool Initialize() override;
|
|
|
|
void Shutdown() override;
|
|
|
|
|
2020-10-09 08:26:21 +00:00
|
|
|
public Q_SLOTS:
|
2019-12-31 06:17:17 +00:00
|
|
|
void ReportError(const char* message) override;
|
|
|
|
void ReportMessage(const char* message) override;
|
2020-12-16 15:17:26 +00:00
|
|
|
void ReportDebuggerMessage(const char* message) override;
|
2020-02-26 09:25:57 +00:00
|
|
|
bool ConfirmMessage(const char* message) override;
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-10-09 08:26:21 +00:00
|
|
|
public:
|
2020-07-13 16:24:11 +00:00
|
|
|
/// Thread-safe settings access.
|
2020-07-21 09:49:04 +00:00
|
|
|
void SetBoolSettingValue(const char* section, const char* key, bool value);
|
|
|
|
void SetIntSettingValue(const char* section, const char* key, int value);
|
|
|
|
void SetFloatSettingValue(const char* section, const char* key, float value);
|
|
|
|
void SetStringSettingValue(const char* section, const char* key, const char* value);
|
|
|
|
void SetStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
|
|
|
|
void RemoveSettingValue(const char* section, const char* key);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-09-13 01:54:51 +00:00
|
|
|
TinyString TranslateString(const char* context, const char* str) const override;
|
|
|
|
std::string TranslateStdString(const char* context, const char* str) const override;
|
2020-08-22 03:01:52 +00:00
|
|
|
|
2020-11-18 13:15:16 +00:00
|
|
|
bool RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) override;
|
2020-12-29 06:29:14 +00:00
|
|
|
void* GetTopLevelWindowHandle() const override;
|
2020-11-18 13:15:16 +00:00
|
|
|
|
2020-03-12 05:32:30 +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
|
|
|
|
2020-03-12 05:32:30 +00:00
|
|
|
ALWAYS_INLINE const HotkeyInfoList& getHotkeyInfoList() const { return GetHotkeyInfoList(); }
|
2020-03-21 14:49:46 +00:00
|
|
|
ALWAYS_INLINE ControllerInterface* getControllerInterface() const { return GetControllerInterface(); }
|
2020-04-13 12:13:46 +00:00
|
|
|
ALWAYS_INLINE bool inBatchMode() const { return InBatchMode(); }
|
2020-08-06 12:08:22 +00:00
|
|
|
ALWAYS_INLINE void requestExit() { RequestExit(); }
|
2020-02-28 07:00:09 +00:00
|
|
|
|
2020-03-12 05:32:30 +00:00
|
|
|
ALWAYS_INLINE bool isOnWorkerThread() const { return QThread::currentThread() == m_worker_thread; }
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-03-12 05:32:30 +00:00
|
|
|
ALWAYS_INLINE MainWindow* getMainWindow() const { return m_main_window; }
|
|
|
|
void setMainWindow(MainWindow* window);
|
2020-06-29 16:46:57 +00:00
|
|
|
HostDisplay* 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);
|
|
|
|
|
2020-03-02 01:08:16 +00:00
|
|
|
/// Fills menu with save state info and handlers.
|
2020-11-10 13:24:07 +00:00
|
|
|
void populateGameListContextMenu(const GameListEntry* entry, QWidget* parent_window, QMenu* menu);
|
2020-03-02 01:08:16 +00:00
|
|
|
|
2020-08-15 10:39:11 +00:00
|
|
|
/// Fills menu with the current playlist entries. The disc index is marked as checked.
|
|
|
|
void populatePlaylistEntryMenu(QMenu* menu);
|
|
|
|
|
2020-09-09 13:44:21 +00:00
|
|
|
/// Fills menu with the current cheat options.
|
|
|
|
void populateCheatsMenu(QMenu* menu);
|
|
|
|
|
2020-06-11 16:47:39 +00:00
|
|
|
ALWAYS_INLINE QString getSavePathForInputProfile(const QString& name) const
|
2020-04-26 15:05:01 +00:00
|
|
|
{
|
2020-06-11 16:47:39 +00:00
|
|
|
return QString::fromStdString(GetSavePathForInputProfile(name.toUtf8().constData()));
|
2020-04-14 15:44:16 +00:00
|
|
|
}
|
2020-06-11 16:47:39 +00:00
|
|
|
ALWAYS_INLINE InputProfileList getInputProfileList() const { return GetInputProfileList(); }
|
2020-04-14 15:44:16 +00:00
|
|
|
void saveInputProfile(const QString& profile_path);
|
|
|
|
|
2020-05-20 13:26:24 +00:00
|
|
|
/// Returns a path relative to the user directory.
|
|
|
|
QString getUserDirectoryRelativePath(const QString& arg) const;
|
|
|
|
|
|
|
|
/// Returns a path relative to the application directory (for system files).
|
|
|
|
QString getProgramDirectoryRelativePath(const QString& arg) const;
|
|
|
|
|
2020-07-28 09:14:44 +00:00
|
|
|
/// Returns a list of supported languages and codes (suffixes for translation files).
|
|
|
|
static std::vector<std::pair<QString, QString>> getAvailableLanguageList();
|
|
|
|
|
2020-08-06 12:08:22 +00:00
|
|
|
/// Returns program directory as a QString.
|
|
|
|
QString getProgramDirectory() const;
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
Q_SIGNALS:
|
2020-02-15 15:14:30 +00:00
|
|
|
void errorReported(const QString& message);
|
|
|
|
void messageReported(const QString& message);
|
2020-12-16 15:17:26 +00:00
|
|
|
void debuggerMessageReported(const QString& message);
|
2020-02-26 09:25:57 +00:00
|
|
|
bool messageConfirmed(const QString& message);
|
2020-06-05 17:44:57 +00:00
|
|
|
void emulationStarting();
|
2019-12-31 06:17:17 +00:00
|
|
|
void emulationStarted();
|
|
|
|
void emulationStopped();
|
|
|
|
void emulationPaused(bool paused);
|
2020-02-15 15:15:18 +00:00
|
|
|
void stateSaved(const QString& game_code, bool global, qint32 slot);
|
2019-12-31 06:17:17 +00:00
|
|
|
void gameListRefreshed();
|
2020-12-26 13:22:24 +00:00
|
|
|
QtDisplayWidget* createDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
2020-06-29 16:46:57 +00:00
|
|
|
QtDisplayWidget* updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
|
2020-11-18 13:15:16 +00:00
|
|
|
void displaySizeRequested(qint32 width, qint32 height);
|
2020-02-26 09:26:14 +00:00
|
|
|
void focusDisplayWidgetRequested();
|
2020-04-22 11:13:51 +00:00
|
|
|
void destroyDisplayRequested();
|
2020-02-09 13:16:25 +00:00
|
|
|
void systemPerformanceCountersUpdated(float speed, float fps, float vps, float avg_frame_time,
|
|
|
|
float worst_frame_time);
|
2020-02-15 15:14:30 +00:00
|
|
|
void runningGameChanged(const QString& filename, const QString& game_code, const QString& game_title);
|
2020-04-13 12:13:46 +00:00
|
|
|
void exitRequested();
|
2020-04-14 15:44:16 +00:00
|
|
|
void inputProfileLoaded();
|
2020-12-27 04:08:13 +00:00
|
|
|
void mouseModeRequested(bool relative, bool hide_cursor);
|
2021-02-26 14:44:53 +00:00
|
|
|
void achievementsLoaded(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
|
2019-12-31 06:17:17 +00:00
|
|
|
|
|
|
|
public Q_SLOTS:
|
2020-02-28 07:00:09 +00:00
|
|
|
void setDefaultSettings();
|
2020-08-20 11:30:11 +00:00
|
|
|
void applySettings(bool display_osd_messages = false);
|
2020-02-28 07:00:09 +00:00
|
|
|
void updateInputMap();
|
2020-04-14 15:44:16 +00:00
|
|
|
void applyInputProfile(const QString& profile_path);
|
2020-09-12 20:01:08 +00:00
|
|
|
void bootSystem(std::shared_ptr<const SystemBootParameters> params);
|
2020-02-15 15:14:49 +00:00
|
|
|
void resumeSystemFromState(const QString& filename, bool boot_on_failure);
|
2020-05-23 05:03:00 +00:00
|
|
|
void resumeSystemFromMostRecentState();
|
2020-02-15 15:14:49 +00:00
|
|
|
void powerOffSystem();
|
2021-01-08 13:42:17 +00:00
|
|
|
void powerOffSystemWithoutSaving();
|
2020-02-15 15:14:49 +00:00
|
|
|
void synchronousPowerOffSystem();
|
2019-12-31 06:17:17 +00:00
|
|
|
void resetSystem();
|
2020-12-16 15:18:13 +00:00
|
|
|
void pauseSystem(bool paused, bool wait_until_paused = false);
|
2020-02-15 15:14:30 +00:00
|
|
|
void changeDisc(const QString& new_disc_filename);
|
2020-08-15 10:39:11 +00:00
|
|
|
void changeDiscFromPlaylist(quint32 index);
|
2020-02-15 15:14:30 +00:00
|
|
|
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-12-08 14:48:00 +00:00
|
|
|
void setAudioOutputVolume(int volume, int fast_forward_volume);
|
2020-07-23 16:55:00 +00:00
|
|
|
void setAudioOutputMuted(bool muted);
|
2020-03-15 12:04:32 +00:00
|
|
|
void startDumpingAudio();
|
|
|
|
void stopDumpingAudio();
|
2020-12-16 15:18:13 +00:00
|
|
|
void singleStepCPU();
|
2020-08-16 13:20:36 +00:00
|
|
|
void dumpRAM(const QString& filename);
|
2021-01-13 09:24:41 +00:00
|
|
|
void dumpVRAM(const QString& filename);
|
|
|
|
void dumpSPURAM(const QString& filename);
|
2020-03-15 14:06:39 +00:00
|
|
|
void saveScreenshot();
|
2020-03-22 11:50:49 +00:00
|
|
|
void redrawDisplayWindow();
|
2020-04-05 12:58:47 +00:00
|
|
|
void toggleFullscreen();
|
2020-09-09 13:44:21 +00:00
|
|
|
void loadCheatList(const QString& filename);
|
|
|
|
void setCheatEnabled(quint32 index, bool enabled);
|
|
|
|
void applyCheat(quint32 index);
|
2020-09-13 10:21:33 +00:00
|
|
|
void reloadPostProcessingShaders();
|
2020-11-18 13:15:16 +00:00
|
|
|
void requestRenderWindowScale(qreal scale);
|
2020-10-19 15:14:49 +00:00
|
|
|
void executeOnEmulationThread(std::function<void()> callback, bool wait = false);
|
2021-02-26 14:44:53 +00:00
|
|
|
void OnAchievementsRefreshed() override;
|
2019-12-31 06:17:17 +00:00
|
|
|
|
|
|
|
private Q_SLOTS:
|
|
|
|
void doStopThread();
|
2021-02-25 16:42:20 +00:00
|
|
|
void onDisplayWindowMouseMoveEvent(int x, int y);
|
|
|
|
void onDisplayWindowMouseButtonEvent(int button, bool pressed);
|
|
|
|
void onDisplayWindowMouseWheelEvent(const QPoint& delta_angle);
|
|
|
|
void onDisplayWindowResized(int width, int height);
|
|
|
|
void onDisplayWindowFocused();
|
|
|
|
void onDisplayWindowKeyEvent(int key, bool pressed);
|
2020-02-15 15:14:53 +00:00
|
|
|
void doBackgroundControllerPoll();
|
2020-07-21 09:58:50 +00:00
|
|
|
void doSaveSettings();
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-01-24 04:49:47 +00:00
|
|
|
protected:
|
2020-02-15 15:14:28 +00:00
|
|
|
bool AcquireHostDisplay() override;
|
|
|
|
void ReleaseHostDisplay() override;
|
2020-04-05 12:58:54 +00:00
|
|
|
bool IsFullscreen() const override;
|
|
|
|
bool SetFullscreen(bool enabled) override;
|
2020-02-28 07:00:09 +00:00
|
|
|
|
2020-04-13 12:13:46 +00:00
|
|
|
void RequestExit() override;
|
2020-02-28 07:00:09 +00:00
|
|
|
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
|
2020-02-15 15:14:28 +00:00
|
|
|
|
|
|
|
void OnSystemCreated() override;
|
|
|
|
void OnSystemPaused(bool paused) override;
|
|
|
|
void OnSystemDestroyed() override;
|
2020-02-09 13:16:25 +00:00
|
|
|
void OnSystemPerformanceCountersUpdated() override;
|
2021-02-21 06:53:14 +00:00
|
|
|
void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code,
|
|
|
|
const std::string& game_title) override;
|
2020-02-28 07:00:09 +00:00
|
|
|
void OnSystemStateSaved(bool global, s32 slot) override;
|
2020-03-21 14:49:46 +00:00
|
|
|
|
2020-04-05 12:58:47 +00:00
|
|
|
void SetDefaultSettings(SettingsInterface& si) override;
|
2021-02-21 10:22:44 +00:00
|
|
|
void ApplySettings(bool display_osd_messages) override;
|
2020-01-24 04:49:47 +00:00
|
|
|
|
2020-12-27 04:08:13 +00:00
|
|
|
void SetMouseMode(bool relative, bool hide_cursor) override;
|
2021-01-30 05:52:36 +00:00
|
|
|
void RunLater(std::function<void()> func) override;
|
2020-12-27 04:08:13 +00:00
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
private:
|
2020-02-15 15:14:53 +00:00
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
BACKGROUND_CONTROLLER_POLLING_INTERVAL =
|
2020-07-21 09:58:50 +00:00
|
|
|
100, /// Interval at which the controllers are polled when the system is not active.
|
|
|
|
|
2021-02-21 16:38:16 +00:00
|
|
|
SETTINGS_SAVE_DELAY = 1000,
|
|
|
|
|
|
|
|
/// Crappy solution to the Qt indices being massive.
|
|
|
|
IMGUI_KEY_MASK = 511,
|
2020-02-15 15:14:53 +00:00
|
|
|
};
|
|
|
|
|
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();
|
|
|
|
|
2020-04-05 12:59:06 +00:00
|
|
|
void setInitResult(bool result);
|
|
|
|
bool waitForInit();
|
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
protected:
|
|
|
|
void run() override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
QtHostInterface* m_parent;
|
2020-04-13 12:13:46 +00:00
|
|
|
std::atomic_bool m_init_result{false};
|
2020-04-05 12:59:06 +00:00
|
|
|
Common::Event m_init_event;
|
2019-12-31 06:17:17 +00:00
|
|
|
};
|
|
|
|
|
2020-02-15 15:14:53 +00:00
|
|
|
void createBackgroundControllerPollTimer();
|
|
|
|
void destroyBackgroundControllerPollTimer();
|
2020-04-29 03:27:58 +00:00
|
|
|
void startBackgroundControllerPollTimer();
|
|
|
|
void stopBackgroundControllerPollTimer();
|
2020-01-24 04:49:49 +00:00
|
|
|
|
2021-02-21 16:38:16 +00:00
|
|
|
void setImGuiFont();
|
|
|
|
void setImGuiKeyMap();
|
2020-06-29 16:46:57 +00:00
|
|
|
|
2019-12-31 06:17:17 +00:00
|
|
|
void createThread();
|
|
|
|
void stopThread();
|
|
|
|
void threadEntryPoint();
|
2020-04-05 12:59:06 +00:00
|
|
|
bool initializeOnThread();
|
|
|
|
void shutdownOnThread();
|
2020-07-28 09:14:44 +00:00
|
|
|
void installTranslator();
|
2020-03-18 12:27:45 +00:00
|
|
|
void renderDisplay();
|
2020-06-29 16:46:57 +00:00
|
|
|
void connectDisplaySignals(QtDisplayWidget* widget);
|
2020-04-22 11:13:51 +00:00
|
|
|
void updateDisplayState();
|
2020-07-21 09:58:50 +00:00
|
|
|
void queueSettingsSave();
|
2020-01-10 03:28:13 +00:00
|
|
|
void wakeThread();
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-07-28 09:14:44 +00:00
|
|
|
std::unique_ptr<QTranslator> m_translator;
|
|
|
|
|
2020-03-12 05:32:30 +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;
|
2020-01-10 03:28:13 +00:00
|
|
|
QEventLoop* m_worker_thread_event_loop = nullptr;
|
2020-10-19 15:14:49 +00:00
|
|
|
Common::Event m_worker_thread_sync_execute_done;
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-01-02 06:13:03 +00:00
|
|
|
std::atomic_bool m_shutdown_flag{false};
|
2019-12-31 06:17:17 +00:00
|
|
|
|
2020-02-15 15:14:53 +00:00
|
|
|
QTimer* m_background_controller_polling_timer = nullptr;
|
2020-07-21 09:58:50 +00:00
|
|
|
std::unique_ptr<QTimer> m_settings_save_timer;
|
2020-04-05 12:58:47 +00:00
|
|
|
|
|
|
|
bool m_is_rendering_to_main = false;
|
|
|
|
bool m_is_fullscreen = false;
|
2020-11-01 14:38:54 +00:00
|
|
|
bool m_is_exclusive_fullscreen = false;
|
2021-02-25 02:51:43 +00:00
|
|
|
bool m_lost_exclusive_fullscreen = false;
|
2020-01-02 06:13:03 +00:00
|
|
|
};
|