#pragma once #include #include #include #include #include #include #include #include #include "emulator.hpp" #include "panda_qt/about_window.hpp" #include "panda_qt/config_window.hpp" #include "panda_qt/screen.hpp" #include "panda_qt/text_editor.hpp" #include "services/hid.hpp" class MainWindow : public QMainWindow { Q_OBJECT private: // Types of messages we might send from the GUI thread to the emulator thread enum class MessageType { LoadROM, Reset, Pause, Resume, TogglePause, DumpRomFS, PressKey, ReleaseKey, LoadLuaScript }; // Tagged union representing our message queue messages struct EmulatorMessage { MessageType type; union { struct { std::filesystem::path* p; } path; struct { u32 key; } key; struct { std::string* str; } string; }; }; // This would normally be an std::unique_ptr but it's shared between threads so definitely not Emulator* emu = nullptr; std::thread emuThread; std::atomic appRunning = true; // Is the application itself running? // Used for synchronizing messages between the emulator and UI std::mutex messageQueueMutex; std::vector messageQueue; ScreenWidget screen; AboutWindow* aboutWindow; ConfigWindow* configWindow; TextEditorWindow* luaEditor; QMenuBar* menuBar = nullptr; void swapEmuBuffer(); void emuThreadMainLoop(); void selectLuaFile(); void selectROM(); void dumpRomFS(); void openLuaEditor(); void showAboutMenu(); void sendMessage(const EmulatorMessage& message); void dispatchMessage(const EmulatorMessage& message); // Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer bool usingGL = false; bool usingVk = false; public: MainWindow(QApplication* app, QWidget* parent = nullptr); ~MainWindow(); void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; void loadLuaScript(const std::string& code); };