From 0132b17af6e95bdc87be28ed5302a4185284d027 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 16 Feb 2025 05:08:39 +0800 Subject: [PATCH 1/5] GHA CI: fix AppImage building Upstream now defaults to static runtime and the previous URL is invalid now. Upstream commits: * https://github.com/linuxdeploy/linuxdeploy/commit/c28054bab6623e72e0e27ffec88c41df5ce46667 * https://github.com/linuxdeploy/linuxdeploy-plugin-qt/commit/ce5291e25979d7d6417551d787f308b88c1b8d76 Also fuse2 is not needed now as stated on: https://github.com/AppImage/type2-runtime?tab=readme-ov-file#type2-runtime- PR #22286. --- .github/workflows/ci_ubuntu.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml index 172876852..c35ca3e30 100644 --- a/.github/workflows/ci_ubuntu.yaml +++ b/.github/workflows/ci_ubuntu.yaml @@ -134,16 +134,15 @@ jobs: - name: Install AppImage run: | - sudo apt install libfuse2 curl \ -L \ -Z \ - -O https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-static-x86_64.AppImage \ - -O https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-static-x86_64.AppImage \ + -O https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \ + -O https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage \ -O https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage chmod +x \ - linuxdeploy-static-x86_64.AppImage \ - linuxdeploy-plugin-qt-static-x86_64.AppImage \ + linuxdeploy-x86_64.AppImage \ + linuxdeploy-plugin-qt-x86_64.AppImage \ linuxdeploy-plugin-appimage-x86_64.AppImage - name: Prepare files for AppImage @@ -156,12 +155,12 @@ jobs: - name: Package AppImage run: | - ./linuxdeploy-static-x86_64.AppImage --appdir qbittorrent --plugin qt + ./linuxdeploy-x86_64.AppImage --appdir qbittorrent --plugin qt rm qbittorrent/apprun-hooks/* cp .github/workflows/helper/appimage/export_vars.sh qbittorrent/apprun-hooks/export_vars.sh NO_APPSTREAM=1 \ OUTPUT=upload/qbittorrent-CI_Ubuntu_x86_64.AppImage \ - ./linuxdeploy-static-x86_64.AppImage --appdir qbittorrent --output appimage + ./linuxdeploy-x86_64.AppImage --appdir qbittorrent --output appimage - name: Upload build artifacts uses: actions/upload-artifact@v4 From 03dc089148f66307075fee044191a33e96bdfa1d Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Tue, 25 Feb 2025 09:11:03 +0300 Subject: [PATCH 2/5] Improve command line parameters serialization PR #22319. Closes #22306. --- src/app/application.cpp | 67 +++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index 1d10731ed..c3c643419 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2024 Vladimir Golovnev + * Copyright (C) 2015-2025 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -124,6 +124,28 @@ namespace const int PIXMAP_CACHE_SIZE = 64 * 1024 * 1024; // 64MiB #endif + const QString PARAM_ADDSTOPPED = u"@addStopped"_s; + const QString PARAM_CATEGORY = u"@category"_s; + const QString PARAM_FIRSTLASTPIECEPRIORITY = u"@firstLastPiecePriority"_s; + const QString PARAM_SAVEPATH = u"@savePath"_s; + const QString PARAM_SEQUENTIAL = u"@sequential"_s; + const QString PARAM_SKIPCHECKING = u"@skipChecking"_s; + const QString PARAM_SKIPDIALOG = u"@skipDialog"_s; + + QString bindParamValue(const QStringView paramName, const QStringView paramValue) + { + return paramName + u'=' + paramValue; + } + + std::pair parseParam(const QStringView param) + { + const qsizetype sepIndex = param.indexOf(u'='); + if (sepIndex >= 0) + return {param.first(sepIndex), param.sliced(sepIndex + 1)}; + + return {param, {}}; + } + QString serializeParams(const QBtCommandLineParameters ¶ms) { QStringList result; @@ -138,85 +160,86 @@ namespace const BitTorrent::AddTorrentParams &addTorrentParams = params.addTorrentParams; if (!addTorrentParams.savePath.isEmpty()) - result.append(u"@savePath=" + addTorrentParams.savePath.data()); + result.append(bindParamValue(PARAM_SAVEPATH, addTorrentParams.savePath.data())); if (addTorrentParams.addStopped.has_value()) - result.append(*addTorrentParams.addStopped ? u"@addStopped=1"_s : u"@addStopped=0"_s); + result.append(bindParamValue(PARAM_ADDSTOPPED, (*addTorrentParams.addStopped ? u"1" : u"0"))); if (addTorrentParams.skipChecking) - result.append(u"@skipChecking"_s); + result.append(PARAM_SKIPCHECKING); if (!addTorrentParams.category.isEmpty()) - result.append(u"@category=" + addTorrentParams.category); + result.append(bindParamValue(PARAM_CATEGORY, addTorrentParams.category)); if (addTorrentParams.sequential) - result.append(u"@sequential"_s); + result.append(PARAM_SEQUENTIAL); if (addTorrentParams.firstLastPiecePriority) - result.append(u"@firstLastPiecePriority"_s); + result.append(PARAM_FIRSTLASTPIECEPRIORITY); if (params.skipDialog.has_value()) - result.append(*params.skipDialog ? u"@skipDialog=1"_s : u"@skipDialog=0"_s); + result.append(bindParamValue(PARAM_SKIPDIALOG, (*params.skipDialog ? u"1" : u"0"))); result += params.torrentSources; return result.join(PARAMS_SEPARATOR); } - QBtCommandLineParameters parseParams(const QString &str) + QBtCommandLineParameters parseParams(const QStringView str) { QBtCommandLineParameters parsedParams; BitTorrent::AddTorrentParams &addTorrentParams = parsedParams.addTorrentParams; - for (QString param : asConst(str.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts))) + for (QStringView param : asConst(str.split(PARAMS_SEPARATOR, Qt::SkipEmptyParts))) { param = param.trimmed(); + const auto [paramName, paramValue] = parseParam(param); // Process strings indicating options specified by the user. - if (param.startsWith(u"@savePath=")) + if (paramName == PARAM_SAVEPATH) { - addTorrentParams.savePath = Path(param.mid(10)); + addTorrentParams.savePath = Path(paramValue.toString()); continue; } - if (param.startsWith(u"@addStopped=")) + if (paramName == PARAM_ADDSTOPPED) { - addTorrentParams.addStopped = (QStringView(param).mid(11).toInt() != 0); + addTorrentParams.addStopped = (paramValue.toInt() != 0); continue; } - if (param == u"@skipChecking") + if (paramName == PARAM_SKIPCHECKING) { addTorrentParams.skipChecking = true; continue; } - if (param.startsWith(u"@category=")) + if (paramName == PARAM_CATEGORY) { - addTorrentParams.category = param.mid(10); + addTorrentParams.category = paramValue.toString(); continue; } - if (param == u"@sequential") + if (paramName == PARAM_SEQUENTIAL) { addTorrentParams.sequential = true; continue; } - if (param == u"@firstLastPiecePriority") + if (paramName == PARAM_FIRSTLASTPIECEPRIORITY) { addTorrentParams.firstLastPiecePriority = true; continue; } - if (param.startsWith(u"@skipDialog=")) + if (paramName == PARAM_SKIPDIALOG) { - parsedParams.skipDialog = (QStringView(param).mid(12).toInt() != 0); + parsedParams.skipDialog = (paramValue.toInt() != 0); continue; } - parsedParams.torrentSources.append(param); + parsedParams.torrentSources.append(param.toString()); } return parsedParams; From 3c6ff0097faeb46ae1f502b1b553e19cb2e0f2d2 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Tue, 25 Feb 2025 18:56:15 +0300 Subject: [PATCH 3/5] Don't miss to declare some of the color IDs PR #22330. Closes #22326. --- src/gui/uithemecommon.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/gui/uithemecommon.h b/src/gui/uithemecommon.h index 31ae5a456..9f1545fe6 100644 --- a/src/gui/uithemecommon.h +++ b/src/gui/uithemecommon.h @@ -80,7 +80,33 @@ inline QHash defaultUIThemeColors() {u"TransferList.StoppedUploading"_s, {Color::Primer::Light::doneFg, Color::Primer::Dark::doneFg}}, {u"TransferList.Moving"_s, {Color::Primer::Light::successFg, Color::Primer::Dark::successFg}}, {u"TransferList.MissingFiles"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}}, - {u"TransferList.Error"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}} + {u"TransferList.Error"_s, {Color::Primer::Light::dangerFg, Color::Primer::Dark::dangerFg}}, + + {u"Palette.Window"_s, {{}, {}}}, + {u"Palette.WindowText"_s, {{}, {}}}, + {u"Palette.Base"_s, {{}, {}}}, + {u"Palette.AlternateBase"_s, {{}, {}}}, + {u"Palette.Text"_s, {{}, {}}}, + {u"Palette.ToolTipBase"_s, {{}, {}}}, + {u"Palette.ToolTipText"_s, {{}, {}}}, + {u"Palette.BrightText"_s, {{}, {}}}, + {u"Palette.Highlight"_s, {{}, {}}}, + {u"Palette.HighlightedText"_s, {{}, {}}}, + {u"Palette.Button"_s, {{}, {}}}, + {u"Palette.ButtonText"_s, {{}, {}}}, + {u"Palette.Link"_s, {{}, {}}}, + {u"Palette.LinkVisited"_s, {{}, {}}}, + {u"Palette.Light"_s, {{}, {}}}, + {u"Palette.Midlight"_s, {{}, {}}}, + {u"Palette.Mid"_s, {{}, {}}}, + {u"Palette.Dark"_s, {{}, {}}}, + {u"Palette.Shadow"_s, {{}, {}}}, + {u"Palette.WindowTextDisabled"_s, {{}, {}}}, + {u"Palette.TextDisabled"_s, {{}, {}}}, + {u"Palette.ToolTipTextDisabled"_s, {{}, {}}}, + {u"Palette.BrightTextDisabled"_s, {{}, {}}}, + {u"Palette.HighlightedTextDisabled"_s, {{}, {}}}, + {u"Palette.ButtonTextDisabled"_s, {{}, {}}} }; } From 13fcd3d6351ff56b4714e89b3a62b40c476a9eca Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Wed, 5 Mar 2025 09:03:00 +0300 Subject: [PATCH 4/5] Add missing includes PR #22362. --- src/base/http/types.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/base/http/types.h b/src/base/http/types.h index 156ddf6c0..4b0b99a59 100644 --- a/src/base/http/types.h +++ b/src/base/http/types.h @@ -29,7 +29,10 @@ #pragma once +#include +#include #include +#include #include #include From ddd8fbd34eddd807fdca6e78f1a307e6b1f2ef23 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Mon, 31 Mar 2025 09:18:16 +0300 Subject: [PATCH 5/5] Add option to enable previous Add new torrent dialog behavior Some people are still unhappy with "standalone window mode" of "Add new torrent dialog" so just provide them with an option to use old "modal dialog mode" in all the current qBittorrent branches. PR #22492 (based on original PR #19874). --- src/base/preferences.cpp | 13 +++++++++++++ src/base/preferences.h | 2 ++ src/gui/advancedsettings.cpp | 5 +++++ src/gui/advancedsettings.h | 1 + src/gui/guiaddtorrentmanager.cpp | 11 +++++++++-- 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 5b3fcb94e..fc9c5a5e5 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -2000,6 +2000,19 @@ void Preferences::setAddNewTorrentDialogSavePathHistoryLength(const int value) setValue(u"AddNewTorrentDialog/SavePathHistoryLength"_s, clampedValue); } +bool Preferences::isAddNewTorrentDialogAttached() const +{ + return value(u"AddNewTorrentDialog/Attached"_s, false); +} + +void Preferences::setAddNewTorrentDialogAttached(const bool attached) +{ + if (attached == isAddNewTorrentDialogAttached()) + return; + + setValue(u"AddNewTorrentDialog/Attached"_s, attached); +} + void Preferences::apply() { if (SettingsStorage::instance()->save()) diff --git a/src/base/preferences.h b/src/base/preferences.h index a106ac7cf..70f5cedcf 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -423,6 +423,8 @@ public: void setAddNewTorrentDialogTopLevel(bool value); int addNewTorrentDialogSavePathHistoryLength() const; void setAddNewTorrentDialogSavePathHistoryLength(int value); + bool isAddNewTorrentDialogAttached() const; + void setAddNewTorrentDialogAttached(bool attached); public slots: void setStatusFilterState(bool checked); diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index 53d50f468..7af38add3 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -97,6 +97,7 @@ namespace ENABLE_SPEED_WIDGET, #ifndef Q_OS_MACOS ENABLE_ICONS_IN_MENUS, + USE_ATTACHED_ADD_NEW_TORRENT_DIALOG, #endif // embedded tracker TRACKER_STATUS, @@ -323,6 +324,7 @@ void AdvancedSettings::saveAdvancedSettings() const pref->setSpeedWidgetEnabled(m_checkBoxSpeedWidgetEnabled.isChecked()); #ifndef Q_OS_MACOS pref->setIconsInMenusEnabled(m_checkBoxIconsInMenusEnabled.isChecked()); + pref->setAddNewTorrentDialogAttached(m_checkBoxAttachedAddNewTorrentDialog.isChecked()); #endif // Tracker @@ -835,6 +837,9 @@ void AdvancedSettings::loadAdvancedSettings() // Enable icons in menus m_checkBoxIconsInMenusEnabled.setChecked(pref->iconsInMenusEnabled()); addRow(ENABLE_ICONS_IN_MENUS, tr("Enable icons in menus"), &m_checkBoxIconsInMenusEnabled); + + m_checkBoxAttachedAddNewTorrentDialog.setChecked(pref->isAddNewTorrentDialogAttached()); + addRow(USE_ATTACHED_ADD_NEW_TORRENT_DIALOG, tr("Attach \"Add new torrent\" dialog to main window"), &m_checkBoxAttachedAddNewTorrentDialog); #endif // Tracker State m_checkBoxTrackerStatus.setChecked(session->isTrackerEnabled()); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 74914b293..6c9db2055 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -108,6 +108,7 @@ private: #ifndef Q_OS_MACOS QCheckBox m_checkBoxIconsInMenusEnabled; + QCheckBox m_checkBoxAttachedAddNewTorrentDialog; #endif #if defined(Q_OS_MACOS) || defined(Q_OS_WIN) diff --git a/src/gui/guiaddtorrentmanager.cpp b/src/gui/guiaddtorrentmanager.cpp index d600a4e17..90ca669ab 100644 --- a/src/gui/guiaddtorrentmanager.cpp +++ b/src/gui/guiaddtorrentmanager.cpp @@ -225,12 +225,19 @@ bool GUIAddTorrentManager::processTorrent(const QString &source if (!hasMetadata) btSession()->downloadMetadata(torrentDescr); +#ifdef Q_OS_MACOS + const bool attached = false; +#else + const bool attached = Preferences::instance()->isAddNewTorrentDialogAttached(); +#endif + // By not setting a parent to the "AddNewTorrentDialog", all those dialogs // will be displayed on top and will not overlap with the main window. - auto *dlg = new AddNewTorrentDialog(torrentDescr, params, nullptr); + auto *dlg = new AddNewTorrentDialog(torrentDescr, params, (attached ? app()->mainWindow() : nullptr)); // Qt::Window is required to avoid showing only two dialog on top (see #12852). // Also improves the general convenience of adding multiple torrents. - dlg->setWindowFlags(Qt::Window); + if (!attached) + dlg->setWindowFlags(Qt::Window); dlg->setAttribute(Qt::WA_DeleteOnClose); m_dialogs[infoHash] = dlg;