diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 11780bfba5..e0381f09e6 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -542,6 +542,11 @@ true true + + true + true + true + true true @@ -762,6 +767,11 @@ true true + + true + true + true + true true @@ -1002,6 +1012,11 @@ true true + + true + true + true + true true @@ -1222,6 +1237,11 @@ true true + + true + true + true + true true @@ -1913,30 +1933,22 @@ - - - - - - - - - - - - - - - - - - - - - - - - + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB "-DBRANCH=$(BRANCH)" -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath) $(QTDIR)\bin\moc.exe;%(FullPath) diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 2b9191716d..27d085edab 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -757,18 +757,6 @@ Gui\update manager - - Generated Files\Release - LLVM - - - Generated Files\Debug - - - Generated Files\Release - - - Generated Files\Debug - LLVM - Gui @@ -883,6 +871,18 @@ Generated Files\Debug - LLVM + + Generated Files\Release - LLVM + + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug - LLVM + diff --git a/rpcs3/rpcs3qt/game_compatibility.cpp b/rpcs3/rpcs3qt/game_compatibility.cpp index c7ef0f4c62..7412643043 100644 --- a/rpcs3/rpcs3qt/game_compatibility.cpp +++ b/rpcs3/rpcs3qt/game_compatibility.cpp @@ -2,6 +2,7 @@ #include "gui_settings.h" #include "progress_dialog.h" +#include #include #include #include @@ -24,7 +25,25 @@ game_compatibility::game_compatibility(std::shared_ptr settings) : m_curl = curl_easy_init(); +#ifdef _WIN32 + // This shouldn't be needed on linux + curl_easy_setopt(m_curl, CURLOPT_CAINFO, "cacert.pem"); +#endif + RequestCompatibility(); + + // We need this signal in order to update the GUI from the main thread + connect(this, &game_compatibility::signal_buffer_update, this, &game_compatibility::handle_buffer_update); +} + +void game_compatibility::handle_buffer_update(int size, int max) +{ + if (m_progress_dialog) + { + m_progress_dialog->setMaximum(max); + m_progress_dialog->setValue(size); + QApplication::processEvents(); + } } size_t game_compatibility::update_buffer(char* data, size_t size) @@ -39,17 +58,17 @@ size_t game_compatibility::update_buffer(char* data, size_t size) m_curl_buf.resize(static_cast(new_size)); memcpy(m_curl_buf.data() + old_size, data, size); + int max = m_progress_dialog ? m_progress_dialog->maximum() : 0; + if (m_actual_dwnld_size < 0) { if (curl_easy_getinfo(m_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &m_actual_dwnld_size) == CURLE_OK && m_actual_dwnld_size > 0) { - if (m_progress_dialog) - m_progress_dialog->setMaximum(static_cast(m_actual_dwnld_size)); + max = static_cast(m_actual_dwnld_size); } } - if (m_progress_dialog) - m_progress_dialog->setValue(static_cast(new_size)); + Q_EMIT signal_buffer_update(static_cast(new_size), max); return size; } @@ -170,19 +189,26 @@ void game_compatibility::RequestCompatibility(bool online) connect(m_progress_dialog, &QProgressDialog::canceled, [this] { m_curl_abort = true; }); connect(m_progress_dialog, &QProgressDialog::finished, m_progress_dialog, &QProgressDialog::deleteLater); - QThread::create([&] + auto thread = QThread::create([&] { const auto result = curl_easy_perform(m_curl); + m_curl_result = result == CURLE_OK; + if (!m_curl_result) + { + Q_EMIT DownloadError(qstr("Curl error: ") + qstr(curl_easy_strerror(result))); + } + }); + connect(thread, &QThread::finished, this, [this, online]() + { if (m_progress_dialog) { m_progress_dialog->close(); m_progress_dialog = nullptr; } - if (result != CURLE_OK) + if (!m_curl_result) { - Q_EMIT DownloadError(qstr("Curl error: ") + qstr(curl_easy_strerror(result))); return; } @@ -213,7 +239,9 @@ void game_compatibility::RequestCompatibility(bool online) compat_log.success("Wrote database to file: %s", sstr(m_filepath)); } - })->start(); + }); + thread->setObjectName("Compat Update"); + thread->start(); // We want to retrieve a new database, therefore refresh gamelist and indicate that Q_EMIT DownloadStarted(); diff --git a/rpcs3/rpcs3qt/game_compatibility.h b/rpcs3/rpcs3qt/game_compatibility.h index bdf50d9fe7..aa7a1f4e37 100644 --- a/rpcs3/rpcs3qt/game_compatibility.h +++ b/rpcs3/rpcs3qt/game_compatibility.h @@ -41,6 +41,7 @@ private: int m_timer_count = 0; QString m_filepath; std::string m_url; + std::atomic m_curl_result = false; std::atomic m_curl_abort = false; double m_actual_dwnld_size = -1.0; CURL *m_curl = nullptr; @@ -71,6 +72,10 @@ Q_SIGNALS: void DownloadStarted(); void DownloadFinished(); void DownloadError(const QString& error); + void signal_buffer_update(int size, int max); + +private Q_SLOTS: + void handle_buffer_update(int size, int max); }; class compat_pixmap : public QPixmap diff --git a/rpcs3/rpcs3qt/update_manager.cpp b/rpcs3/rpcs3qt/update_manager.cpp index 2d21b47617..1402361051 100644 --- a/rpcs3/rpcs3qt/update_manager.cpp +++ b/rpcs3/rpcs3qt/update_manager.cpp @@ -6,6 +6,7 @@ #include "Crypto/sha256.h" #include "Emu/System.h" +#include #include #include #include @@ -48,6 +49,18 @@ update_manager::update_manager() // This shouldn't be needed on linux curl_easy_setopt(m_curl, CURLOPT_CAINFO, "cacert.pem"); #endif + + // We need this signal in order to update the GUI from the main thread + connect(this, &update_manager::signal_buffer_update, this, &update_manager::handle_buffer_update); +} + +void update_manager::handle_buffer_update(int size) +{ + if (m_progress_dialog && m_update_dialog) + { + m_progress_dialog->setValue(size); + QApplication::processEvents(); + } } size_t update_manager::update_buffer(char* data, size_t size) @@ -62,10 +75,7 @@ size_t update_manager::update_buffer(char* data, size_t size) m_curl_buf.resize(static_cast(new_size)); memcpy(m_curl_buf.data() + old_size, data, size); - if (m_progress_dialog && m_update_dialog) - { - m_progress_dialog->setValue(static_cast(new_size)); - } + Q_EMIT signal_buffer_update(static_cast(new_size)); return size; } @@ -90,7 +100,7 @@ void update_manager::check_for_updates(bool automatic, QWidget* parent) m_progress_dialog->setAutoReset(false); m_progress_dialog->show(); - connect(m_progress_dialog, &QProgressDialog::canceled, [&]() { m_curl_abort = true; }); + connect(m_progress_dialog, &QProgressDialog::canceled, [this]() { m_curl_abort = true; }); connect(m_progress_dialog, &QProgressDialog::finished, m_progress_dialog, &QProgressDialog::deleteLater); const std::string request_url = m_update_url + rpcs3::get_commit_and_hash().second; @@ -98,36 +108,42 @@ void update_manager::check_for_updates(bool automatic, QWidget* parent) curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, curl_write_cb); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this); - bool result_json = false; + auto thread = QThread::create([this] + { + const auto curl_result = curl_easy_perform(m_curl); + m_curl_result = curl_result == CURLE_OK; - if (const auto curl_result = curl_easy_perform(m_curl); curl_result != CURLE_OK) - { - update_log.error("Curl error(query): %s", curl_easy_strerror(curl_result)); - } - else - { - result_json = handle_json(automatic); - } - - if (!result_json && !m_curl_abort) - { - if (!automatic) + if (!m_curl_result) { - QMessageBox::warning(m_parent, tr("Auto-updater"), tr("An error occurred during the auto-updating process.\nCheck the log for more information.")); + update_log.error("Curl error(query): %s", curl_easy_strerror(curl_result)); } + }); + connect(thread, &QThread::finished, this, [this, automatic]() + { + const bool result_json = m_curl_result && handle_json(automatic); - if (m_progress_dialog) + if (!result_json && !m_curl_abort) { - m_progress_dialog->close(); - m_progress_dialog = nullptr; + if (!automatic) + { + QMessageBox::warning(m_parent, tr("Auto-updater"), tr("An error occurred during the auto-updating process.\nCheck the log for more information.")); + } + + if (m_progress_dialog) + { + m_progress_dialog->close(); + m_progress_dialog = nullptr; + } } - } + }); + thread->setObjectName("RPCS3 Update Check"); + thread->start(); } bool update_manager::handle_json(bool automatic) { const QJsonObject json_data = QJsonDocument::fromJson(m_curl_buf).object(); - const int return_code = json_data["return_code"].toInt(-255); + const int return_code = json_data["return_code"].toInt(-255); bool hash_found = true; @@ -207,8 +223,8 @@ bool update_manager::handle_json(bool automatic) if (hash_found) { // Calculates how old the build is - std::string cur_date = json_data["current_build"]["datetime"].toString().toStdString(); - std::string lts_date = latest["datetime"].toString().toStdString(); + const std::string cur_date = json_data["current_build"]["datetime"].toString().toStdString(); + const std::string lts_date = latest["datetime"].toString().toStdString(); tm cur_tm, lts_tm; QString timediff = ""; @@ -228,7 +244,7 @@ bool update_manager::handle_json(bool automatic) time_t cur_time = mktime(&cur_tm); time_t lts_time = mktime(<s_tm); - s64 u_timediff = static_cast(std::difftime(lts_time, cur_time)); + const s64 u_timediff = static_cast(std::difftime(lts_time, cur_time)); update_log.notice("Current: %lld, latest: %lld, difference: %lld", static_cast(cur_time), static_cast(lts_time), u_timediff); timediff = tr("Your version is %1 day(s), %2 hour(s) and %3 minute(s) old.").arg(u_timediff / (60 * 60 * 24)).arg((u_timediff / (60 * 60)) % 24).arg((u_timediff / 60) % 60); @@ -261,19 +277,20 @@ bool update_manager::handle_json(bool automatic) m_curl_buf.clear(); - QThread::create([this, automatic] + auto thread = QThread::create([this] { - bool result_rpcs3 = false; + const auto curl_result = curl_easy_perform(m_curl); + m_curl_result = curl_result == CURLE_OK; - if (const auto curl_result = curl_easy_perform(m_curl); curl_result != CURLE_OK) + if (!m_curl_result) { update_log.error("Curl error(download): %s", curl_easy_strerror(curl_result)); } - else - { - result_rpcs3 = handle_rpcs3(); - } - + }); + connect(thread, &QThread::finished, this, [this, automatic]() + { + const bool result_rpcs3 = m_curl_result && handle_rpcs3(); + if (!result_rpcs3 && !m_curl_abort) { if (!automatic) @@ -287,7 +304,9 @@ bool update_manager::handle_json(bool automatic) m_progress_dialog = nullptr; } } - })->start(); + }); + thread->setObjectName("RPCS3 Updater"); + thread->start(); return true; } @@ -358,7 +377,7 @@ bool update_manager::handle_rpcs3() m_progress_dialog->setWindowTitle(tr("Updating RPCS3")); // Move the appimage/exe and replace with new appimage - std::string move_dest = replace_path + "_old"; + const std::string move_dest = replace_path + "_old"; fs::rename(replace_path, move_dest, true); fs::file new_appimage(replace_path, fs::read + fs::write + fs::create + fs::trunc); if (!new_appimage) @@ -448,7 +467,8 @@ bool update_manager::handle_rpcs3() CrcGenerateTable(); SzArEx_Init(&db); - auto error_free7z = [&]() { + auto error_free7z = [&]() + { SzArEx_Free(&db, &allocImp); ISzAlloc_Free(&allocImp, lookStream.buf); @@ -482,7 +502,7 @@ bool update_manager::handle_rpcs3() size_t outBufferSize = 0; // Creates temp folder for moving active files - std::string tmp_folder = Emulator::GetEmuDir() + m_tmp_folder; + const std::string tmp_folder = Emulator::GetEmuDir() + m_tmp_folder; fs::create_dir(tmp_folder); for (UInt32 i = 0; i < db.NumFiles; i++) @@ -526,7 +546,7 @@ bool update_manager::handle_rpcs3() break; } - if (size_t pos = name.find_last_of('/'); pos != umax) + if (const size_t pos = name.find_last_of('/'); pos != umax) { update_log.trace("Creating path: %s", name.substr(0, pos)); fs::create_path(name.substr(0, pos)); @@ -584,13 +604,12 @@ bool update_manager::handle_rpcs3() return false; #endif - m_progress_dialog->close(); QMessageBox::information(m_parent, tr("Auto-updater"), tr("Update successful!")); #ifdef _WIN32 - int ret = _wexecl(orig_path, orig_path, nullptr); + const int ret = _wexecl(orig_path, orig_path, nullptr); #else - int ret = execl(replace_path.c_str(), replace_path.c_str(), nullptr); + const int ret = execl(replace_path.c_str(), replace_path.c_str(), nullptr); #endif if (ret == -1) { diff --git a/rpcs3/rpcs3qt/update_manager.h b/rpcs3/rpcs3qt/update_manager.h index 2027d7b7d8..07f21e1ee5 100644 --- a/rpcs3/rpcs3qt/update_manager.h +++ b/rpcs3/rpcs3qt/update_manager.h @@ -11,11 +11,12 @@ class progress_dialog; class update_manager final : public QObject { + Q_OBJECT + private: const std::string m_update_url = "https://update.rpcs3.net/?api=v1&c="; const std::string m_tmp_folder = "/rpcs3_old/"; -private: std::atomic m_update_dialog = false; progress_dialog* m_progress_dialog = nullptr; QWidget* m_parent = nullptr; @@ -23,16 +24,22 @@ private: CURL *m_curl = nullptr; QByteArray m_curl_buf; std::atomic m_curl_abort = false; + std::atomic m_curl_result = false; std::string m_expected_hash; u64 m_expected_size = 0; -private: bool handle_json(bool automatic); bool handle_rpcs3(); public: update_manager(); void check_for_updates(bool automatic, QWidget* parent = nullptr); - size_t update_buffer(char *data, size_t size); + size_t update_buffer(char* data, size_t size); + +Q_SIGNALS: + void signal_buffer_update(int size); + +private Q_SLOTS: + void handle_buffer_update(int size); };