mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Qt updater integration, based on QtAutoUpdater
This commit is contained in:
		
							parent
							
								
									ee5aecee3f
								
							
						
					
					
						commit
						2e6c80d1aa
					
				
					 11 changed files with 651 additions and 28 deletions
				
			
		|  | @ -23,9 +23,10 @@ set(SRCS | ||||||
|             debugger/profiler.cpp |             debugger/profiler.cpp | ||||||
|             debugger/registers.cpp |             debugger/registers.cpp | ||||||
|             debugger/wait_tree.cpp |             debugger/wait_tree.cpp | ||||||
|             aboutdialog.cpp |             updater/updater.cpp | ||||||
|             util/spinbox.cpp |             util/spinbox.cpp | ||||||
|             util/util.cpp |             util/util.cpp | ||||||
|  |             aboutdialog.cpp | ||||||
|             bootmanager.cpp |             bootmanager.cpp | ||||||
|             game_list.cpp |             game_list.cpp | ||||||
|             hotkeys.cpp |             hotkeys.cpp | ||||||
|  | @ -56,6 +57,8 @@ set(HEADERS | ||||||
|             debugger/profiler.h |             debugger/profiler.h | ||||||
|             debugger/registers.h |             debugger/registers.h | ||||||
|             debugger/wait_tree.h |             debugger/wait_tree.h | ||||||
|  |             updater/updater.h | ||||||
|  |             updater/updater_p.h | ||||||
|             util/spinbox.h |             util/spinbox.h | ||||||
|             util/util.h |             util/util.h | ||||||
|             aboutdialog.h |             aboutdialog.h | ||||||
|  |  | ||||||
|  | @ -157,6 +157,12 @@ void Config::ReadValues() { | ||||||
|     qt_config->beginGroup("UI"); |     qt_config->beginGroup("UI"); | ||||||
|     UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); |     UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); | ||||||
| 
 | 
 | ||||||
|  |     qt_config->beginGroup("Updater"); | ||||||
|  |     UISettings::values.check_for_update_on_start = | ||||||
|  |         qt_config->value("check_for_update_on_start", true).toBool(); | ||||||
|  |     UISettings::values.update_on_close = qt_config->value("update_on_close", false).toBool(); | ||||||
|  |     qt_config->endGroup(); | ||||||
|  | 
 | ||||||
|     qt_config->beginGroup("UILayout"); |     qt_config->beginGroup("UILayout"); | ||||||
|     UISettings::values.geometry = qt_config->value("geometry").toByteArray(); |     UISettings::values.geometry = qt_config->value("geometry").toByteArray(); | ||||||
|     UISettings::values.state = qt_config->value("state").toByteArray(); |     UISettings::values.state = qt_config->value("state").toByteArray(); | ||||||
|  | @ -307,6 +313,11 @@ void Config::SaveValues() { | ||||||
|     qt_config->beginGroup("UI"); |     qt_config->beginGroup("UI"); | ||||||
|     qt_config->setValue("theme", UISettings::values.theme); |     qt_config->setValue("theme", UISettings::values.theme); | ||||||
| 
 | 
 | ||||||
|  |     qt_config->beginGroup("Updater"); | ||||||
|  |     qt_config->setValue("check_for_update_on_start", UISettings::values.check_for_update_on_start); | ||||||
|  |     qt_config->setValue("update_on_close", UISettings::values.update_on_close); | ||||||
|  |     qt_config->endGroup(); | ||||||
|  | 
 | ||||||
|     qt_config->beginGroup("UILayout"); |     qt_config->beginGroup("UILayout"); | ||||||
|     qt_config->setValue("geometry", UISettings::values.geometry); |     qt_config->setValue("geometry", UISettings::values.geometry); | ||||||
|     qt_config->setValue("state", UISettings::values.state); |     qt_config->setValue("state", UISettings::values.state); | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) | ||||||
|     this->setConfiguration(); |     this->setConfiguration(); | ||||||
| 
 | 
 | ||||||
|     ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); |     ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | ||||||
|  |     ui->updateBox->setVisible(UISettings::values.updater_found); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ConfigureGeneral::~ConfigureGeneral() {} | ConfigureGeneral::~ConfigureGeneral() {} | ||||||
|  | @ -29,6 +30,9 @@ void ConfigureGeneral::setConfiguration() { | ||||||
|     ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); |     ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); | ||||||
|     ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit); |     ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit); | ||||||
| 
 | 
 | ||||||
|  |     ui->toggle_update_check->setChecked(UISettings::values.check_for_update_on_start); | ||||||
|  |     ui->toggle_auto_update->setChecked(UISettings::values.update_on_close); | ||||||
|  | 
 | ||||||
|     // The first item is "auto-select" with actual value -1, so plus one here will do the trick
 |     // The first item is "auto-select" with actual value -1, so plus one here will do the trick
 | ||||||
|     ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1); |     ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1); | ||||||
| 
 | 
 | ||||||
|  | @ -40,6 +44,10 @@ void ConfigureGeneral::applyConfiguration() { | ||||||
|     UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); |     UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | ||||||
|     UISettings::values.theme = |     UISettings::values.theme = | ||||||
|         ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); |         ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); | ||||||
|  | 
 | ||||||
|  |     UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked(); | ||||||
|  |     UISettings::values.update_on_close = ui->toggle_auto_update->isChecked(); | ||||||
|  | 
 | ||||||
|     Settings::values.region_value = ui->region_combobox->currentIndex() - 1; |     Settings::values.region_value = ui->region_combobox->currentIndex() - 1; | ||||||
|     Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); |     Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); | ||||||
|     Settings::Apply(); |     Settings::Apply(); | ||||||
|  |  | ||||||
|  | @ -25,16 +25,16 @@ | ||||||
|         <item> |         <item> | ||||||
|          <layout class="QVBoxLayout" name="verticalLayout_2"> |          <layout class="QVBoxLayout" name="verticalLayout_2"> | ||||||
|           <item> |           <item> | ||||||
|            <widget class="QCheckBox" name="toggle_deepscan"> |            <widget class="QCheckBox" name="toggle_check_exit"> | ||||||
|             <property name="text"> |             <property name="text"> | ||||||
|              <string>Search sub-directories for games</string> |              <string>Confirm exit while emulation is running</string> | ||||||
|             </property> |             </property> | ||||||
|            </widget> |            </widget> | ||||||
|           </item> |           </item> | ||||||
|           <item> |           <item> | ||||||
|            <widget class="QCheckBox" name="toggle_check_exit"> |            <widget class="QCheckBox" name="toggle_deepscan"> | ||||||
|             <property name="text"> |             <property name="text"> | ||||||
|              <string>Confirm exit while emulation is running</string> |              <string>Search sub-directories for games</string> | ||||||
|             </property> |             </property> | ||||||
|            </widget> |            </widget> | ||||||
|           </item> |           </item> | ||||||
|  | @ -44,24 +44,51 @@ | ||||||
|       </widget> |       </widget> | ||||||
|      </item> |      </item> | ||||||
|      <item> |      <item> | ||||||
|        <widget class="QGroupBox" name="groupBox_2"> |       <widget class="QGroupBox" name="updateBox"> | ||||||
|          <property name="title"> |        <property name="title"> | ||||||
|            <string>Performance</string> |         <string>Updates</string> | ||||||
|          </property> |        </property> | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout_7"> |        <layout class="QHBoxLayout" name="horizontalLayout_update"> | ||||||
|            <item> |         <item> | ||||||
|              <layout class="QVBoxLayout" name="verticalLayout_5"> |          <layout class="QVBoxLayout" name="verticalLayout_update"> | ||||||
|                <item> |           <item> | ||||||
|                  <widget class="QCheckBox" name="toggle_cpu_jit"> |            <widget class="QCheckBox" name="toggle_update_check"> | ||||||
|                    <property name="text"> |             <property name="text"> | ||||||
|                      <string>Enable CPU JIT</string> |              <string>Check for updates on start</string> | ||||||
|                    </property> |             </property> | ||||||
|                  </widget> |            </widget> | ||||||
|                </item> |           </item> | ||||||
|              </layout> |           <item> | ||||||
|            </item> |            <widget class="QCheckBox" name="toggle_auto_update"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Silently auto update after closing</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|          </layout> |          </layout> | ||||||
|        </widget> |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|  |      </item> | ||||||
|  |      <item> | ||||||
|  |       <widget class="QGroupBox" name="groupBox_2"> | ||||||
|  |        <property name="title"> | ||||||
|  |         <string>Performance</string> | ||||||
|  |        </property> | ||||||
|  |        <layout class="QHBoxLayout" name="horizontalLayout_7"> | ||||||
|  |         <item> | ||||||
|  |          <layout class="QVBoxLayout" name="verticalLayout_5"> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QCheckBox" name="toggle_cpu_jit"> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Enable CPU JIT</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|  |          </layout> | ||||||
|  |         </item> | ||||||
|  |        </layout> | ||||||
|  |       </widget> | ||||||
|      </item> |      </item> | ||||||
|      <item> |      <item> | ||||||
|       <widget class="QGroupBox" name="groupBox_4"> |       <widget class="QGroupBox" name="groupBox_4"> | ||||||
|  | @ -149,8 +176,7 @@ | ||||||
|              </widget> |              </widget> | ||||||
|             </item> |             </item> | ||||||
|             <item> |             <item> | ||||||
|              <widget class="QComboBox" name="theme_combobox"> |              <widget class="QComboBox" name="theme_combobox"/> | ||||||
|              </widget> |  | ||||||
|             </item> |             </item> | ||||||
|            </layout> |            </layout> | ||||||
|           </item> |           </item> | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ | ||||||
| #include "citra_qt/hotkeys.h" | #include "citra_qt/hotkeys.h" | ||||||
| #include "citra_qt/main.h" | #include "citra_qt/main.h" | ||||||
| #include "citra_qt/ui_settings.h" | #include "citra_qt/ui_settings.h" | ||||||
|  | #include "citra_qt/updater/updater.h" | ||||||
| #include "common/logging/backend.h" | #include "common/logging/backend.h" | ||||||
| #include "common/logging/filter.h" | #include "common/logging/filter.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
|  | @ -100,6 +101,7 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | ||||||
|     InitializeDebugWidgets(); |     InitializeDebugWidgets(); | ||||||
|     InitializeRecentFileMenuActions(); |     InitializeRecentFileMenuActions(); | ||||||
|     InitializeHotkeys(); |     InitializeHotkeys(); | ||||||
|  |     ShowUpdaterWidgets(); | ||||||
| 
 | 
 | ||||||
|     SetDefaultUIGeometry(); |     SetDefaultUIGeometry(); | ||||||
|     RestoreUIState(); |     RestoreUIState(); | ||||||
|  | @ -118,6 +120,10 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | ||||||
|     // Show one-time "callout" messages to the user
 |     // Show one-time "callout" messages to the user
 | ||||||
|     ShowCallouts(); |     ShowCallouts(); | ||||||
| 
 | 
 | ||||||
|  |     if (UISettings::values.check_for_update_on_start) { | ||||||
|  |         CheckForUpdates(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     QStringList args = QApplication::arguments(); |     QStringList args = QApplication::arguments(); | ||||||
|     if (args.length() >= 2) { |     if (args.length() >= 2) { | ||||||
|         BootGame(args[1]); |         BootGame(args[1]); | ||||||
|  | @ -139,6 +145,10 @@ void GMainWindow::InitializeWidgets() { | ||||||
|     game_list = new GameList(this); |     game_list = new GameList(this); | ||||||
|     ui.horizontalLayout->addWidget(game_list); |     ui.horizontalLayout->addWidget(game_list); | ||||||
| 
 | 
 | ||||||
|  |     // Setup updater
 | ||||||
|  |     updater = new Updater(this); | ||||||
|  |     UISettings::values.updater_found = updater->HasUpdater(); | ||||||
|  | 
 | ||||||
|     // Create status bar
 |     // Create status bar
 | ||||||
|     message_label = new QLabel(); |     message_label = new QLabel(); | ||||||
|     // Configured separately for left alignment
 |     // Configured separately for left alignment
 | ||||||
|  | @ -268,6 +278,13 @@ void GMainWindow::InitializeHotkeys() { | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void GMainWindow::ShowUpdaterWidgets() { | ||||||
|  |     ui.action_Check_For_Updates->setVisible(UISettings::values.updater_found); | ||||||
|  |     ui.action_Open_Maintenance_Tool->setVisible(UISettings::values.updater_found); | ||||||
|  | 
 | ||||||
|  |     connect(updater, &Updater::CheckUpdatesDone, this, &GMainWindow::OnUpdateFound); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void GMainWindow::SetDefaultUIGeometry() { | void GMainWindow::SetDefaultUIGeometry() { | ||||||
|     // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
 |     // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
 | ||||||
|     const QRect screenRect = QApplication::desktop()->screenGeometry(this); |     const QRect screenRect = QApplication::desktop()->screenGeometry(this); | ||||||
|  | @ -346,6 +363,10 @@ void GMainWindow::ConnectMenuEvents() { | ||||||
|     connect(ui.action_FAQ, &QAction::triggered, |     connect(ui.action_FAQ, &QAction::triggered, | ||||||
|             []() { QDesktopServices::openUrl(QUrl("https://citra-emu.org/wiki/faq/")); }); |             []() { QDesktopServices::openUrl(QUrl("https://citra-emu.org/wiki/faq/")); }); | ||||||
|     connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnMenuAboutCitra); |     connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnMenuAboutCitra); | ||||||
|  |     connect(ui.action_Check_For_Updates, &QAction::triggered, this, | ||||||
|  |             &GMainWindow::OnCheckForUpdates); | ||||||
|  |     connect(ui.action_Open_Maintenance_Tool, &QAction::triggered, this, | ||||||
|  |             &GMainWindow::OnOpenUpdater); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnDisplayTitleBars(bool show) { | void GMainWindow::OnDisplayTitleBars(bool show) { | ||||||
|  | @ -368,6 +389,46 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void GMainWindow::OnCheckForUpdates() { | ||||||
|  |     CheckForUpdates(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GMainWindow::CheckForUpdates() { | ||||||
|  |     if (updater->CheckForUpdates()) { | ||||||
|  |         LOG_INFO(Frontend, "Update check started"); | ||||||
|  |     } else { | ||||||
|  |         LOG_WARNING(Frontend, "Unable to start check for updates"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GMainWindow::OnUpdateFound(bool found, bool error) { | ||||||
|  |     if (error) { | ||||||
|  |         LOG_WARNING(Frontend, "Update check failed"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!found) { | ||||||
|  |         LOG_INFO(Frontend, "No updates found"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LOG_INFO(Frontend, "Update found!"); | ||||||
|  |     auto result = QMessageBox::question( | ||||||
|  |         this, tr("Update available!"), | ||||||
|  |         tr("An update for Citra is available. Do you wish to install it now?<br /><br />" | ||||||
|  |            "This <b>will</b> terminate emulation, if it is running."), | ||||||
|  |         QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); | ||||||
|  | 
 | ||||||
|  |     if (result == QMessageBox::Yes) { | ||||||
|  |         updater->LaunchUIOnExit(); | ||||||
|  |         close(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void GMainWindow::OnOpenUpdater() { | ||||||
|  |     updater->LaunchUI(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool GMainWindow::LoadROM(const QString& filename) { | bool GMainWindow::LoadROM(const QString& filename) { | ||||||
|     // Shutdown previous session if the emu thread is still active...
 |     // Shutdown previous session if the emu thread is still active...
 | ||||||
|     if (emu_thread != nullptr) |     if (emu_thread != nullptr) | ||||||
|  |  | ||||||
|  | @ -2,8 +2,7 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #ifndef _CITRA_QT_MAIN_HXX_ | #pragma once | ||||||
| #define _CITRA_QT_MAIN_HXX_ |  | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <QMainWindow> | #include <QMainWindow> | ||||||
|  | @ -24,6 +23,7 @@ class GRenderWindow; | ||||||
| class MicroProfileDialog; | class MicroProfileDialog; | ||||||
| class ProfilerWidget; | class ProfilerWidget; | ||||||
| class RegistersWidget; | class RegistersWidget; | ||||||
|  | class Updater; | ||||||
| class WaitTreeWidget; | class WaitTreeWidget; | ||||||
| class AboutDialog; | class AboutDialog; | ||||||
| 
 | 
 | ||||||
|  | @ -82,6 +82,8 @@ private: | ||||||
|     void ShutdownGame(); |     void ShutdownGame(); | ||||||
| 
 | 
 | ||||||
|     void ShowCallouts(); |     void ShowCallouts(); | ||||||
|  |     void ShowUpdaterWidgets(); | ||||||
|  |     void CheckForUpdates(); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Stores the filename in the recently loaded files list. |      * Stores the filename in the recently loaded files list. | ||||||
|  | @ -134,6 +136,9 @@ private slots: | ||||||
|     void OnCoreError(Core::System::ResultStatus, std::string); |     void OnCoreError(Core::System::ResultStatus, std::string); | ||||||
|     /// Called whenever a user selects Help->About Citra
 |     /// Called whenever a user selects Help->About Citra
 | ||||||
|     void OnMenuAboutCitra(); |     void OnMenuAboutCitra(); | ||||||
|  |     void OnUpdateFound(bool found, bool error); | ||||||
|  |     void OnCheckForUpdates(); | ||||||
|  |     void OnOpenUpdater(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void UpdateStatusBar(); |     void UpdateStatusBar(); | ||||||
|  | @ -166,6 +171,7 @@ private: | ||||||
|     GraphicsVertexShaderWidget* graphicsVertexShaderWidget; |     GraphicsVertexShaderWidget* graphicsVertexShaderWidget; | ||||||
|     GraphicsTracingWidget* graphicsTracingWidget; |     GraphicsTracingWidget* graphicsTracingWidget; | ||||||
|     WaitTreeWidget* waitTreeWidget; |     WaitTreeWidget* waitTreeWidget; | ||||||
|  |     Updater* updater; | ||||||
| 
 | 
 | ||||||
|     QAction* actions_recent_files[max_recent_files_item]; |     QAction* actions_recent_files[max_recent_files_item]; | ||||||
| 
 | 
 | ||||||
|  | @ -174,5 +180,3 @@ protected: | ||||||
|     void dragEnterEvent(QDragEnterEvent* event) override; |     void dragEnterEvent(QDragEnterEvent* event) override; | ||||||
|     void dragMoveEvent(QDragMoveEvent* event) override; |     void dragMoveEvent(QDragMoveEvent* event) override; | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| #endif // _CITRA_QT_MAIN_HXX_
 |  | ||||||
|  |  | ||||||
|  | @ -96,6 +96,9 @@ | ||||||
|     <property name="title"> |     <property name="title"> | ||||||
|      <string>&Help</string> |      <string>&Help</string> | ||||||
|     </property> |     </property> | ||||||
|  |     <addaction name="action_Check_For_Updates"/> | ||||||
|  |     <addaction name="action_Open_Maintenance_Tool"/> | ||||||
|  |     <addaction name="separator"/> | ||||||
|     <addaction name="action_FAQ"/> |     <addaction name="action_FAQ"/> | ||||||
|     <addaction name="action_About"/> |     <addaction name="action_About"/> | ||||||
|    </widget> |    </widget> | ||||||
|  | @ -211,6 +214,19 @@ | ||||||
|     <string>Fullscreen</string> |     <string>Fullscreen</string> | ||||||
|    </property> |    </property> | ||||||
|   </action> |   </action> | ||||||
|  |   <action name="action_Open_Maintenance_Tool"> | ||||||
|  |    <property name="text"> | ||||||
|  |     <string>Modify Citra Install</string> | ||||||
|  |    </property> | ||||||
|  |    <property name="toolTip"> | ||||||
|  |     <string>Opens the maintenance tool to modify your Citra installation</string> | ||||||
|  |    </property> | ||||||
|  |   </action> | ||||||
|  |   <action name="action_Check_For_Updates"> | ||||||
|  |    <property name="text"> | ||||||
|  |     <string>Check for Updates</string> | ||||||
|  |    </property> | ||||||
|  |   </action> | ||||||
|  </widget> |  </widget> | ||||||
|  <resources/> |  <resources/> | ||||||
| </ui> | </ui> | ||||||
|  |  | ||||||
|  | @ -39,6 +39,10 @@ struct Values { | ||||||
|     bool confirm_before_closing; |     bool confirm_before_closing; | ||||||
|     bool first_start; |     bool first_start; | ||||||
| 
 | 
 | ||||||
|  |     bool updater_found; | ||||||
|  |     bool update_on_close; | ||||||
|  |     bool check_for_update_on_start; | ||||||
|  | 
 | ||||||
|     QString roms_path; |     QString roms_path; | ||||||
|     QString symbols_path; |     QString symbols_path; | ||||||
|     QString gamedir; |     QString gamedir; | ||||||
|  |  | ||||||
							
								
								
									
										304
									
								
								src/citra_qt/updater/updater.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								src/citra_qt/updater/updater.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,304 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | //
 | ||||||
|  | // Based on the original work by Felix Barx
 | ||||||
|  | // Copyright (c) 2015, Felix Barz
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | 
 | ||||||
|  | #include <QCoreApplication> | ||||||
|  | #include <QDir> | ||||||
|  | #include <QFileInfo> | ||||||
|  | #include <QTimer> | ||||||
|  | #include <QXmlStreamReader> | ||||||
|  | #include "citra_qt/ui_settings.h" | ||||||
|  | #include "citra_qt/updater/updater.h" | ||||||
|  | #include "citra_qt/updater/updater_p.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | 
 | ||||||
|  | #ifdef Q_OS_OSX | ||||||
|  | #define DEFAULT_TOOL_PATH QStringLiteral("../../../../maintenancetool") | ||||||
|  | #else | ||||||
|  | #define DEFAULT_TOOL_PATH QStringLiteral("../maintenancetool") | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | Updater::Updater(QObject* parent) : Updater(DEFAULT_TOOL_PATH, parent) {} | ||||||
|  | 
 | ||||||
|  | Updater::Updater(const QString& maintenance_tool_path, QObject* parent) | ||||||
|  |     : QObject(parent), backend(std::make_unique<UpdaterPrivate>(this)) { | ||||||
|  |     backend->tool_path = UpdaterPrivate::ToSystemExe(maintenance_tool_path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Updater::~Updater() = default; | ||||||
|  | 
 | ||||||
|  | bool Updater::ExitedNormally() const { | ||||||
|  |     return backend->normal_exit; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int Updater::ErrorCode() const { | ||||||
|  |     return backend->last_error_code; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QByteArray Updater::ErrorLog() const { | ||||||
|  |     return backend->last_error_log; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Updater::IsRunning() const { | ||||||
|  |     return backend->running; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QList<Updater::UpdateInfo> Updater::LatestUpdateInfo() const { | ||||||
|  |     return backend->update_info; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Updater::HasUpdater() const { | ||||||
|  |     return backend->HasUpdater(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Updater::CheckForUpdates() { | ||||||
|  |     return backend->StartUpdateCheck(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Updater::AbortUpdateCheck(int max_delay, bool async) { | ||||||
|  |     backend->StopUpdateCheck(max_delay, async); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Updater::LaunchUI() { | ||||||
|  |     backend->LaunchUI(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Updater::SilentlyUpdate() { | ||||||
|  |     backend->SilentlyUpdate(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Updater::LaunchUIOnExit() { | ||||||
|  |     backend->LaunchUIOnExit(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Updater::UpdateInfo::UpdateInfo() = default; | ||||||
|  | 
 | ||||||
|  | Updater::UpdateInfo::UpdateInfo(const Updater::UpdateInfo&) = default; | ||||||
|  | 
 | ||||||
|  | Updater::UpdateInfo::UpdateInfo(QString name, QString version, quint64 size) | ||||||
|  |     : name(std::move(name)), version(std::move(version)), size(size) {} | ||||||
|  | 
 | ||||||
|  | UpdaterPrivate::UpdaterPrivate(Updater* parent_ptr) : QObject(nullptr), parent(parent_ptr) { | ||||||
|  |     connect(qApp, &QCoreApplication::aboutToQuit, this, &UpdaterPrivate::AboutToExit, | ||||||
|  |             Qt::DirectConnection); | ||||||
|  |     qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | UpdaterPrivate::~UpdaterPrivate() { | ||||||
|  |     if (main_process && main_process->state() != QProcess::NotRunning) { | ||||||
|  |         main_process->kill(); | ||||||
|  |         main_process->waitForFinished(1000); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString UpdaterPrivate::ToSystemExe(QString base_path) { | ||||||
|  | #if defined(Q_OS_WIN32) | ||||||
|  |     if (!base_path.endsWith(QStringLiteral(".exe"))) | ||||||
|  |         return base_path + QStringLiteral(".exe"); | ||||||
|  |     else | ||||||
|  |         return base_path; | ||||||
|  | #elif defined(Q_OS_OSX) | ||||||
|  |     if (base_path.endsWith(QStringLiteral(".app"))) | ||||||
|  |         base_path.truncate(base_path.lastIndexOf(QStringLiteral("."))); | ||||||
|  |     return base_path + QStringLiteral(".app/Contents/MacOS/") + QFileInfo(base_path).fileName(); | ||||||
|  | #elif defined(Q_OS_UNIX) | ||||||
|  |     return base_path; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool UpdaterPrivate::HasUpdater() const { | ||||||
|  |     QFileInfo tool_info(QCoreApplication::applicationDirPath(), tool_path); | ||||||
|  |     return tool_info.exists(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool UpdaterPrivate::StartUpdateCheck() { | ||||||
|  |     if (running || !HasUpdater()) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     update_info.clear(); | ||||||
|  |     normal_exit = true; | ||||||
|  |     last_error_code = EXIT_SUCCESS; | ||||||
|  |     last_error_log.clear(); | ||||||
|  | 
 | ||||||
|  |     QFileInfo tool_info(QCoreApplication::applicationDirPath(), tool_path); | ||||||
|  |     main_process = new QProcess(this); | ||||||
|  |     main_process->setProgram(tool_info.absoluteFilePath()); | ||||||
|  |     main_process->setArguments({QStringLiteral("--checkupdates"), QStringLiteral("-v")}); | ||||||
|  | 
 | ||||||
|  |     connect(main_process, | ||||||
|  |             static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, | ||||||
|  |             &UpdaterPrivate::UpdaterReady, Qt::QueuedConnection); | ||||||
|  |     connect(main_process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), | ||||||
|  |             this, &UpdaterPrivate::UpdaterError, Qt::QueuedConnection); | ||||||
|  | 
 | ||||||
|  |     main_process->start(QIODevice::ReadOnly); | ||||||
|  |     running = true; | ||||||
|  | 
 | ||||||
|  |     emit parent->UpdateInfoChanged(update_info); | ||||||
|  |     emit parent->RunningChanged(true); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::StopUpdateCheck(int delay, bool async) { | ||||||
|  |     if (main_process == nullptr || main_process->state() == QProcess::NotRunning) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (delay > 0) { | ||||||
|  |         main_process->terminate(); | ||||||
|  |         if (async) { | ||||||
|  | 			QTimer *timer = new QTimer(this); | ||||||
|  | 			timer->setSingleShot(true); | ||||||
|  | 
 | ||||||
|  | 			connect(timer, &QTimer::timeout, [=]() { | ||||||
|  | 				StopUpdateCheck(0, false); | ||||||
|  | 				timer->deleteLater(); | ||||||
|  | 			}); | ||||||
|  | 
 | ||||||
|  | 			timer->start(delay); | ||||||
|  |         } else { | ||||||
|  |             if (!main_process->waitForFinished(delay)) { | ||||||
|  |                 main_process->kill(); | ||||||
|  |                 main_process->waitForFinished(100); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         main_process->kill(); | ||||||
|  |         main_process->waitForFinished(100); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | XMLParseResult UpdaterPrivate::ParseResult(const QByteArray& output, | ||||||
|  |                                            QList<Updater::UpdateInfo>& out) { | ||||||
|  |     const auto out_string = QString::fromUtf8(output); | ||||||
|  |     const auto xml_begin = out_string.indexOf(QStringLiteral("<updates>")); | ||||||
|  |     if (xml_begin < 0) | ||||||
|  |         return XMLParseResult::NoUpdate; | ||||||
|  |     const auto xml_end = out_string.indexOf(QStringLiteral("</updates>"), xml_begin); | ||||||
|  |     if (xml_end < 0) | ||||||
|  |         return XMLParseResult::NoUpdate; | ||||||
|  | 
 | ||||||
|  |     QList<Updater::UpdateInfo> updates; | ||||||
|  |     QXmlStreamReader reader(out_string.mid(xml_begin, (xml_end + 10) - xml_begin)); | ||||||
|  | 
 | ||||||
|  |     reader.readNextStartElement(); | ||||||
|  |     // should always work because it was search for
 | ||||||
|  |     if (reader.name() != QStringLiteral("updates")) { | ||||||
|  |         return XMLParseResult::InvalidXML; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     while (reader.readNextStartElement()) { | ||||||
|  |         if (reader.name() != QStringLiteral("update")) | ||||||
|  |             return XMLParseResult::InvalidXML; | ||||||
|  | 
 | ||||||
|  |         auto ok = false; | ||||||
|  |         Updater::UpdateInfo info( | ||||||
|  |             reader.attributes().value(QStringLiteral("name")).toString(), | ||||||
|  |             reader.attributes().value(QStringLiteral("version")).toString(), | ||||||
|  |             reader.attributes().value(QStringLiteral("size")).toULongLong(&ok)); | ||||||
|  | 
 | ||||||
|  |         if (info.name.isEmpty() || info.version.isNull() || !ok) | ||||||
|  |             return XMLParseResult::InvalidXML; | ||||||
|  |         if (reader.readNextStartElement()) | ||||||
|  |             return XMLParseResult::InvalidXML; | ||||||
|  | 
 | ||||||
|  |         updates.append(info); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (reader.hasError()) { | ||||||
|  |         LOG_ERROR(Frontend, "Cannot read xml for update: %s", | ||||||
|  |                   reader.errorString().toStdString().c_str()); | ||||||
|  |         return XMLParseResult::InvalidXML; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     out = updates; | ||||||
|  |     return XMLParseResult::Success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::UpdaterReady(int exit_code, QProcess::ExitStatus exit_status) { | ||||||
|  |     if (main_process == nullptr) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (exit_status != QProcess::NormalExit) { | ||||||
|  |         UpdaterError(QProcess::Crashed); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     normal_exit = true; | ||||||
|  |     last_error_code = exit_code; | ||||||
|  |     last_error_log = main_process->readAllStandardError(); | ||||||
|  |     const auto update_out = main_process->readAllStandardOutput(); | ||||||
|  |     main_process->deleteLater(); | ||||||
|  |     main_process = nullptr; | ||||||
|  | 
 | ||||||
|  |     running = false; | ||||||
|  |     emit parent->RunningChanged(false); | ||||||
|  | 
 | ||||||
|  |     QList<Updater::UpdateInfo> update_info; | ||||||
|  |     auto err = ParseResult(update_out, update_info); | ||||||
|  |     bool has_error = false; | ||||||
|  | 
 | ||||||
|  |     if (err == XMLParseResult::Success) { | ||||||
|  |         if (!update_info.isEmpty()) | ||||||
|  |             emit parent->UpdateInfoChanged(update_info); | ||||||
|  |     } else if (err == XMLParseResult::InvalidXML) { | ||||||
|  |         has_error = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     emit parent->CheckUpdatesDone(!update_info.isEmpty(), has_error); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::UpdaterError(QProcess::ProcessError error) { | ||||||
|  |     if (main_process) { | ||||||
|  |         normal_exit = false; | ||||||
|  |         last_error_code = error; | ||||||
|  |         last_error_log = main_process->errorString().toUtf8(); | ||||||
|  |         main_process->deleteLater(); | ||||||
|  |         main_process = nullptr; | ||||||
|  | 
 | ||||||
|  |         running = false; | ||||||
|  |         emit parent->RunningChanged(false); | ||||||
|  |         emit parent->CheckUpdatesDone(false, true); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::LaunchWithArguments(const QStringList& args) { | ||||||
|  |     if (!HasUpdater()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     QFileInfo tool_info(QCoreApplication::applicationDirPath(), tool_path); | ||||||
|  | 
 | ||||||
|  |     if (!QProcess::startDetached(tool_info.absoluteFilePath(), args, tool_info.absolutePath())) { | ||||||
|  |         LOG_WARNING(Frontend, "Unable to start program %s", | ||||||
|  |                     tool_info.absoluteFilePath().toStdString().c_str()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::LaunchUI() { | ||||||
|  |     LOG_INFO(Frontend, "Launching update UI..."); | ||||||
|  |     LaunchWithArguments(run_arguments); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::SilentlyUpdate() { | ||||||
|  |     LOG_INFO(Frontend, "Launching silent update..."); | ||||||
|  |     LaunchWithArguments(silent_arguments); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::AboutToExit() { | ||||||
|  |     if (launch_ui_on_exit) { | ||||||
|  |         LaunchUI(); | ||||||
|  |     } else if (UISettings::values.update_on_close) { | ||||||
|  |         SilentlyUpdate(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UpdaterPrivate::LaunchUIOnExit() { | ||||||
|  |     launch_ui_on_exit = true; | ||||||
|  | } | ||||||
							
								
								
									
										120
									
								
								src/citra_qt/updater/updater.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/citra_qt/updater/updater.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,120 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | //
 | ||||||
|  | // Based on the original work by Felix Barx
 | ||||||
|  | // Copyright (c) 2015, Felix Barz
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Redistribution and use in source and binary forms, with or without
 | ||||||
|  | // modification, are permitted provided that the following conditions are met:
 | ||||||
|  | //
 | ||||||
|  | // * Redistributions of source code must retain the above copyright notice, this
 | ||||||
|  | // list of conditions and the following disclaimer.
 | ||||||
|  | //
 | ||||||
|  | // * Redistributions in binary form must reproduce the above copyright notice,
 | ||||||
|  | // this list of conditions and the following disclaimer in the documentation
 | ||||||
|  | // and/or other materials provided with the distribution.
 | ||||||
|  | //
 | ||||||
|  | // * Neither the name of QtAutoUpdater nor the names of its
 | ||||||
|  | // contributors may be used to endorse or promote products derived from
 | ||||||
|  | // this software without specific prior written permission.
 | ||||||
|  | //
 | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | ||||||
|  | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | ||||||
|  | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | ||||||
|  | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | ||||||
|  | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | ||||||
|  | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | ||||||
|  | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | ||||||
|  | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | ||||||
|  | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <QDateTime> | ||||||
|  | #include <QList> | ||||||
|  | #include <QScopedPointer> | ||||||
|  | #include <QString> | ||||||
|  | #include <QStringList> | ||||||
|  | 
 | ||||||
|  | class UpdaterPrivate; | ||||||
|  | 
 | ||||||
|  | /// The main updater. Can check for updates and run the maintenancetool as updater
 | ||||||
|  | class Updater : public QObject { | ||||||
|  |     Q_OBJECT; | ||||||
|  | 
 | ||||||
|  |     /// Specifies whether the updater is currently checking for updates or not
 | ||||||
|  |     Q_PROPERTY(bool running READ IsRunning NOTIFY RunningChanged); | ||||||
|  |     /// Holds extended information about the last update check
 | ||||||
|  |     Q_PROPERTY(QList<UpdateInfo> update_info READ LatestUpdateInfo NOTIFY UpdateInfoChanged); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     /// Provides information about updates for components
 | ||||||
|  |     struct UpdateInfo { | ||||||
|  |         /// The name of the component that has an update
 | ||||||
|  |         QString name; | ||||||
|  |         /// The new version for that compontent
 | ||||||
|  |         QString version; | ||||||
|  |         /// The update download size (in Bytes)
 | ||||||
|  |         quint64 size = 0; | ||||||
|  | 
 | ||||||
|  |         /// Default Constructor
 | ||||||
|  |         UpdateInfo(); | ||||||
|  |         /// Copy Constructor
 | ||||||
|  |         UpdateInfo(const UpdateInfo& other); | ||||||
|  |         /// Constructor that takes name, version and size
 | ||||||
|  |         UpdateInfo(QString name, QString version, quint64 size); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     /// Default constructor
 | ||||||
|  |     explicit Updater(QObject* parent = nullptr); | ||||||
|  |     /// Constructor with an explicitly set path
 | ||||||
|  |     explicit Updater(const QString& maintenance_tool_path, QObject* parent = nullptr); | ||||||
|  |     /// Destroys the updater and kills the update check (if running)
 | ||||||
|  |     ~Updater(); | ||||||
|  | 
 | ||||||
|  |     /// Returns `true`, if the updater exited normally
 | ||||||
|  |     bool ExitedNormally() const; | ||||||
|  |     /// Returns the mainetancetools error code of the last update
 | ||||||
|  |     int ErrorCode() const; | ||||||
|  |     /// returns the error output (stderr) of the last update
 | ||||||
|  |     QByteArray ErrorLog() const; | ||||||
|  | 
 | ||||||
|  |     /// readAcFn{Updater::running}
 | ||||||
|  |     bool IsRunning() const; | ||||||
|  |     /// readAcFn{Updater::updateInfo}
 | ||||||
|  |     QList<UpdateInfo> LatestUpdateInfo() const; | ||||||
|  | 
 | ||||||
|  |     /// Launches the updater UI formally
 | ||||||
|  |     void LaunchUI(); | ||||||
|  | 
 | ||||||
|  |     /// Silently updates the application in the background
 | ||||||
|  |     void SilentlyUpdate(); | ||||||
|  | 
 | ||||||
|  |     /// Checks to see if a updater application is available
 | ||||||
|  |     bool HasUpdater() const; | ||||||
|  | 
 | ||||||
|  |     /// Instead of silently updating, explictly open the UI on shutdown
 | ||||||
|  |     void LaunchUIOnExit(); | ||||||
|  | 
 | ||||||
|  | public slots: | ||||||
|  |     /// Starts checking for updates
 | ||||||
|  |     bool CheckForUpdates(); | ||||||
|  |     /// Aborts checking for updates
 | ||||||
|  |     void AbortUpdateCheck(int max_delay = 5000, bool async = false); | ||||||
|  | 
 | ||||||
|  | signals: | ||||||
|  |     /// Will be emitted as soon as the updater finished checking for updates
 | ||||||
|  |     void CheckUpdatesDone(bool has_updates, bool has_error); | ||||||
|  | 
 | ||||||
|  |     /// notifyAcFn{Updater::running}
 | ||||||
|  |     void RunningChanged(bool running); | ||||||
|  |     /// notifyAcFn{Updater::updateInfo}
 | ||||||
|  |     void UpdateInfoChanged(QList<Updater::UpdateInfo> update_info); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::unique_ptr<UpdaterPrivate> backend; | ||||||
|  | }; | ||||||
							
								
								
									
										66
									
								
								src/citra_qt/updater/updater_p.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/citra_qt/updater/updater_p.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | //
 | ||||||
|  | // Based on the original work by Felix Barx
 | ||||||
|  | // Copyright (c) 2015, Felix Barz
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <QtCore/QProcess> | ||||||
|  | #include "citra_qt/updater/updater.h" | ||||||
|  | 
 | ||||||
|  | enum class XMLParseResult { | ||||||
|  |     Success, | ||||||
|  |     NoUpdate, | ||||||
|  |     InvalidXML, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class UpdaterPrivate : public QObject { | ||||||
|  |     Q_OBJECT; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     explicit UpdaterPrivate(Updater* parent_ptr); | ||||||
|  |     ~UpdaterPrivate(); | ||||||
|  | 
 | ||||||
|  |     static QString ToSystemExe(QString base_path); | ||||||
|  | 
 | ||||||
|  |     bool HasUpdater() const; | ||||||
|  | 
 | ||||||
|  |     bool StartUpdateCheck(); | ||||||
|  | 
 | ||||||
|  |     void LaunchWithArguments(const QStringList& args); | ||||||
|  |     void LaunchUI(); | ||||||
|  |     void SilentlyUpdate(); | ||||||
|  | 
 | ||||||
|  |     void LaunchUIOnExit(); | ||||||
|  | 
 | ||||||
|  | public slots: | ||||||
|  | 	void StopUpdateCheck(int delay, bool async); | ||||||
|  |     void UpdaterReady(int exit_code, QProcess::ExitStatus exit_status); | ||||||
|  |     void UpdaterError(QProcess::ProcessError error); | ||||||
|  | 
 | ||||||
|  |     void AboutToExit(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     XMLParseResult ParseResult(const QByteArray& output, QList<Updater::UpdateInfo>& out); | ||||||
|  | 
 | ||||||
|  |     Updater* parent; | ||||||
|  | 
 | ||||||
|  |     QString tool_path{}; | ||||||
|  |     QList<Updater::UpdateInfo> update_info{}; | ||||||
|  |     bool normal_exit = true; | ||||||
|  |     int last_error_code = 0; | ||||||
|  |     QByteArray last_error_log = EXIT_SUCCESS; | ||||||
|  | 
 | ||||||
|  |     bool running = false; | ||||||
|  |     QProcess* main_process = nullptr; | ||||||
|  | 
 | ||||||
|  |     bool launch_ui_on_exit = false; | ||||||
|  | 
 | ||||||
|  |     QStringList run_arguments{"--updater"}; | ||||||
|  |     QStringList silent_arguments{"--silentUpdate"}; | ||||||
|  | 
 | ||||||
|  |     friend class Updater; | ||||||
|  | }; | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue