mainwindow.h (11235B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "controllersettingswindow.h" 7 #include "displaywidget.h" 8 #include "settingswindow.h" 9 #include "ui_mainwindow.h" 10 11 #include "core/types.h" 12 13 #include "util/window_info.h" 14 15 #include <QtCore/QThread> 16 #include <QtWidgets/QLabel> 17 #include <QtWidgets/QMainWindow> 18 #include <QtWidgets/QMenu> 19 #include <QtWidgets/QStackedWidget> 20 #include <memory> 21 #include <optional> 22 23 class QLabel; 24 class QThread; 25 class QProgressBar; 26 27 class MainWindow; 28 class GameListWidget; 29 class EmuThread; 30 class AutoUpdaterDialog; 31 class MemoryCardEditorWindow; 32 class CheatManagerWindow; 33 class DebuggerWindow; 34 class MemoryScannerWindow; 35 36 struct SystemBootParameters; 37 38 class GPUDevice; 39 namespace Achievements { 40 enum class LoginRequestReason; 41 } 42 namespace GameList { 43 struct Entry; 44 } 45 46 class MainWindow final : public QMainWindow 47 { 48 Q_OBJECT 49 50 public: 51 /// This class is a scoped lock on the system, which prevents it from running while 52 /// the object exists. Its purpose is to be used for blocking/modal popup boxes, 53 /// where the VM needs to exit fullscreen temporarily. 54 class SystemLock 55 { 56 public: 57 SystemLock(SystemLock&& lock); 58 SystemLock(const SystemLock&) = delete; 59 ~SystemLock(); 60 61 /// Returns the parent widget, which can be used for any popup dialogs. 62 ALWAYS_INLINE QWidget* getDialogParent() const { return m_dialog_parent; } 63 64 /// Cancels any pending unpause/fullscreen transition. 65 /// Call when you're going to destroy the system anyway. 66 void cancelResume(); 67 68 private: 69 SystemLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen); 70 friend MainWindow; 71 72 QWidget* m_dialog_parent; 73 bool m_was_paused; 74 bool m_was_fullscreen; 75 }; 76 77 public: 78 explicit MainWindow(); 79 ~MainWindow(); 80 81 /// Performs update check if enabled in settings. 82 void startupUpdateCheck(); 83 84 /// Opens memory card editor with the specified paths. 85 void openMemoryCardEditor(const QString& card_a_path, const QString& card_b_path); 86 87 /// Locks the system by pausing it, while a popup dialog is displayed. 88 SystemLock pauseAndLockSystem(); 89 90 /// Force quits the application. 91 void quit(); 92 93 /// Accessors for the status bar widgets, updated by the emulation thread. 94 ALWAYS_INLINE QLabel* getStatusRendererWidget() const { return m_status_renderer_widget; } 95 ALWAYS_INLINE QLabel* getStatusResolutionWidget() const { return m_status_resolution_widget; } 96 ALWAYS_INLINE QLabel* getStatusFPSWidget() const { return m_status_fps_widget; } 97 ALWAYS_INLINE QLabel* getStatusVPSWidget() const { return m_status_vps_widget; } 98 99 /// Accessors for child windows. 100 CheatManagerWindow* getCheatManagerWindow() const { return m_cheat_manager_window; } 101 102 /// Opens the editor for a specific input profile. 103 void openInputProfileEditor(const std::string_view name); 104 105 public Q_SLOTS: 106 /// Updates debug menu visibility (hides if disabled). 107 void updateDebugMenuVisibility(); 108 109 void refreshGameList(bool invalidate_cache); 110 void refreshGameListModel(); 111 void cancelGameListRefresh(); 112 113 void runOnUIThread(const std::function<void()>& func); 114 bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool save_state = true); 115 void requestExit(bool allow_confirm = true); 116 void checkForSettingChanges(); 117 std::optional<WindowInfo> getWindowInfo(); 118 119 void checkForUpdates(bool display_message); 120 void recreate(); 121 122 void* getNativeWindowId(); 123 124 private Q_SLOTS: 125 void reportError(const QString& title, const QString& message); 126 bool confirmMessage(const QString& title, const QString& message); 127 void onStatusMessage(const QString& message); 128 129 std::optional<WindowInfo> acquireRenderWindow(bool recreate_window, bool fullscreen, bool render_to_main, 130 bool surfaceless, bool use_main_window_pos); 131 void displayResizeRequested(qint32 width, qint32 height); 132 void releaseRenderWindow(); 133 void focusDisplayWidget(); 134 void onMouseModeRequested(bool relative_mode, bool hide_cursor); 135 136 void onSettingsResetToDefault(bool system, bool controller); 137 void onSystemStarting(); 138 void onSystemStarted(); 139 void onSystemDestroyed(); 140 void onSystemPaused(); 141 void onSystemResumed(); 142 void onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title); 143 void onMediaCaptureStarted(); 144 void onMediaCaptureStopped(); 145 void onAchievementsLoginRequested(Achievements::LoginRequestReason reason); 146 void onAchievementsChallengeModeChanged(bool enabled); 147 void onApplicationStateChanged(Qt::ApplicationState state); 148 149 void onStartFileActionTriggered(); 150 void onStartDiscActionTriggered(); 151 void onStartBIOSActionTriggered(); 152 void onChangeDiscFromFileActionTriggered(); 153 void onChangeDiscFromGameListActionTriggered(); 154 void onChangeDiscFromDeviceActionTriggered(); 155 void onChangeDiscMenuAboutToShow(); 156 void onChangeDiscMenuAboutToHide(); 157 void onLoadStateMenuAboutToShow(); 158 void onSaveStateMenuAboutToShow(); 159 void onCheatsActionTriggered(); 160 void onCheatsMenuAboutToShow(); 161 void onStartFullscreenUITriggered(); 162 void onFullscreenUIStateChange(bool running); 163 void onRemoveDiscActionTriggered(); 164 void onViewToolbarActionToggled(bool checked); 165 void onViewLockToolbarActionToggled(bool checked); 166 void onViewStatusBarActionToggled(bool checked); 167 void onViewGameListActionTriggered(); 168 void onViewGameGridActionTriggered(); 169 void onViewSystemDisplayTriggered(); 170 void onViewGamePropertiesActionTriggered(); 171 void onGitHubRepositoryActionTriggered(); 172 void onIssueTrackerActionTriggered(); 173 void onDiscordServerActionTriggered(); 174 void onAboutActionTriggered(); 175 void onCheckForUpdatesActionTriggered(); 176 void onToolsMemoryCardEditorTriggered(); 177 void onToolsMemoryScannerTriggered(); 178 void onToolsCoverDownloaderTriggered(); 179 void onToolsMediaCaptureToggled(bool checked); 180 void onToolsOpenDataDirectoryTriggered(); 181 void onSettingsTriggeredFromToolbar(); 182 183 void onGameListRefreshComplete(); 184 void onGameListRefreshProgress(const QString& status, int current, int total); 185 void onGameListSelectionChanged(); 186 void onGameListEntryActivated(); 187 void onGameListEntryContextMenuRequested(const QPoint& point); 188 189 void onUpdateCheckComplete(); 190 191 void openCheatManager(); 192 void openCPUDebugger(); 193 194 protected: 195 void showEvent(QShowEvent* event) override; 196 void closeEvent(QCloseEvent* event) override; 197 void changeEvent(QEvent* event) override; 198 void dragEnterEvent(QDragEnterEvent* event) override; 199 void dropEvent(QDropEvent* event) override; 200 void moveEvent(QMoveEvent* event) override; 201 void resizeEvent(QResizeEvent* event) override; 202 203 #ifdef _WIN32 204 bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override; 205 #endif 206 207 private: 208 /// Initializes the window. Call once at startup. 209 void initialize(); 210 211 void setupAdditionalUi(); 212 void connectSignals(); 213 214 void updateEmulationActions(bool starting, bool running, bool cheevos_challenge_mode); 215 void updateStatusBarWidgetVisibility(); 216 void updateWindowTitle(); 217 void updateWindowState(bool force_visible = false); 218 void updateCheatActionsVisibility(); 219 220 void setProgressBar(int current, int total); 221 void clearProgressBar(); 222 223 QWidget* getContentParent(); 224 QWidget* getDisplayContainer() const; 225 bool isShowingGameList() const; 226 bool isRenderingFullscreen() const; 227 bool isRenderingToMain() const; 228 bool shouldHideMouseCursor() const; 229 bool shouldHideMainWindow() const; 230 231 void switchToGameListView(); 232 void switchToEmulationView(); 233 void saveStateToConfig(); 234 void restoreStateFromConfig(); 235 void saveDisplayWindowGeometryToConfig(); 236 void restoreDisplayWindowGeometryFromConfig(); 237 void createDisplayWidget(bool fullscreen, bool render_to_main, bool use_main_window_pos); 238 void destroyDisplayWidget(bool show_game_list); 239 void updateDisplayWidgetCursor(); 240 void updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen); 241 242 SettingsWindow* getSettingsWindow(); 243 void doSettings(const char* category = nullptr); 244 245 ControllerSettingsWindow* getControllerSettingsWindow(); 246 void doControllerSettings(ControllerSettingsWindow::Category category = ControllerSettingsWindow::Category::Count); 247 248 void updateDebugMenuCPUExecutionMode(); 249 void updateDebugMenuGPURenderer(); 250 void updateDebugMenuCropMode(); 251 std::string getDeviceDiscPath(const QString& title); 252 void setGameListEntryCoverImage(const GameList::Entry* entry); 253 void clearGameListEntryPlayTime(const GameList::Entry* entry); 254 void updateTheme(); 255 void reloadThemeSpecificImages(); 256 void onSettingsThemeChanged(); 257 void destroySubWindows(); 258 259 void registerForDeviceNotifications(); 260 void unregisterForDeviceNotifications(); 261 262 /// Fills menu with save state info and handlers. 263 void populateGameListContextMenu(const GameList::Entry* entry, QWidget* parent_window, QMenu* menu); 264 265 void populateLoadStateMenu(const char* game_serial, QMenu* menu); 266 void populateSaveStateMenu(const char* game_serial, QMenu* menu); 267 268 /// Fills menu with the current playlist entries. The disc index is marked as checked. 269 void populateChangeDiscSubImageMenu(QMenu* menu, QActionGroup* action_group); 270 271 /// Fills menu with the current cheat options. 272 void populateCheatsMenu(QMenu* menu); 273 274 const GameList::Entry* resolveDiscSetEntry(const GameList::Entry* entry, 275 std::unique_lock<std::recursive_mutex>& lock); 276 std::shared_ptr<SystemBootParameters> getSystemBootParameters(std::string file); 277 std::optional<bool> promptForResumeState(const std::string& save_state_path); 278 void startFile(std::string path, std::optional<std::string> save_path, std::optional<bool> fast_boot); 279 void startFileOrChangeDisc(const QString& path); 280 void promptForDiscChange(const QString& path); 281 282 Ui::MainWindow m_ui; 283 284 GameListWidget* m_game_list_widget = nullptr; 285 286 DisplayWidget* m_display_widget = nullptr; 287 DisplayContainer* m_display_container = nullptr; 288 289 QProgressBar* m_status_progress_widget = nullptr; 290 QLabel* m_status_renderer_widget = nullptr; 291 QLabel* m_status_fps_widget = nullptr; 292 QLabel* m_status_vps_widget = nullptr; 293 QLabel* m_status_resolution_widget = nullptr; 294 295 QMenu* m_settings_toolbar_menu = nullptr; 296 297 SettingsWindow* m_settings_window = nullptr; 298 ControllerSettingsWindow* m_controller_settings_window = nullptr; 299 300 AutoUpdaterDialog* m_auto_updater_dialog = nullptr; 301 MemoryCardEditorWindow* m_memory_card_editor_window = nullptr; 302 CheatManagerWindow* m_cheat_manager_window = nullptr; 303 DebuggerWindow* m_debugger_window = nullptr; 304 MemoryScannerWindow* m_memory_scanner_window = nullptr; 305 306 bool m_was_paused_by_focus_loss = false; 307 bool m_open_debugger_on_start = false; 308 bool m_relative_mouse_mode = false; 309 bool m_hide_mouse_cursor = false; 310 311 bool m_display_created = false; 312 bool m_save_states_invalidated = false; 313 bool m_was_paused_on_surface_loss = false; 314 bool m_was_disc_change_request = false; 315 bool m_is_closing = false; 316 317 #ifdef _WIN32 318 void* m_device_notification_handle = nullptr; 319 #endif 320 }; 321 322 extern MainWindow* g_main_window;