mirror of
https://github.com/transmission/transmission
synced 2024-12-21 23:32:35 +00:00
Move Qt client's tr_main() into a separate file (#7076)
Support special (optional) `--` argument to explicitly separate options from filenames. Support special `---` argument to separate client arguments from Qt arguments.
This commit is contained in:
parent
7543126789
commit
d8413493d0
4 changed files with 270 additions and 195 deletions
|
@ -6,9 +6,6 @@
|
|||
#include "Application.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <QIcon>
|
||||
|
@ -17,7 +14,6 @@
|
|||
#include <QProcess>
|
||||
#include <QRect>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QtDebug>
|
||||
|
||||
#ifdef QT_DBUS_LIB
|
||||
#include <QDBusConnection>
|
||||
|
@ -31,10 +27,7 @@
|
|||
|
||||
#include <libtransmission/transmission.h>
|
||||
|
||||
#include <libtransmission/tr-getopt.h>
|
||||
#include <libtransmission/utils.h>
|
||||
#include <libtransmission/values.h>
|
||||
#include <libtransmission/version.h>
|
||||
|
||||
#include "AccessibleSqueezeLabel.h"
|
||||
#include "AddData.h"
|
||||
|
@ -49,22 +42,7 @@
|
|||
namespace
|
||||
{
|
||||
|
||||
std::array<tr_option, 8> const Opts = {
|
||||
tr_option{ 'g', "config-dir", "Where to look for configuration files", "g", true, "<path>" },
|
||||
{ 'm', "minimized", "Start minimized in system tray", "m", false, nullptr },
|
||||
{ 'p', "port", "Port to use when connecting to an existing session", "p", true, "<port>" },
|
||||
{ 'r', "remote", "Connect to an existing session at the specified hostname", "r", true, "<host>" },
|
||||
{ 'u', "username", "Username to use when connecting to an existing session", "u", true, "<username>" },
|
||||
{ 'v', "version", "Show version number and exit", "v", false, nullptr },
|
||||
{ 'w', "password", "Password to use when connecting to an existing session", "w", true, "<password>" },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
};
|
||||
|
||||
char const* getUsage()
|
||||
{
|
||||
return "Usage:\n"
|
||||
" transmission [OPTIONS...] [torrent files]";
|
||||
}
|
||||
auto const ConfigName = QLatin1String("transmission");
|
||||
|
||||
auto constexpr StatsRefreshIntervalMsec = 3000;
|
||||
auto constexpr SessionRefreshIntervalMsec = 3000;
|
||||
|
@ -116,12 +94,17 @@ QAccessibleInterface* accessibleFactory(QString const& className, QObject* objec
|
|||
|
||||
} // namespace
|
||||
|
||||
Application::Application(int& argc, char** argv)
|
||||
Application::Application(
|
||||
std::unique_ptr<Prefs> prefs,
|
||||
bool minimized,
|
||||
QString const& config_dir,
|
||||
QStringList const& filenames,
|
||||
int& argc,
|
||||
char** argv)
|
||||
: QApplication{ argc, argv }
|
||||
, config_name_{ QStringLiteral("transmission") }
|
||||
, display_name_{ QStringLiteral("transmission-qt") }
|
||||
, prefs_(std::move(prefs))
|
||||
{
|
||||
setApplicationName(config_name_);
|
||||
setApplicationName(ConfigName);
|
||||
loadTranslations();
|
||||
initUnits();
|
||||
|
||||
|
@ -140,113 +123,6 @@ Application::Application(int& argc, char** argv)
|
|||
setAttribute(Qt::AA_DontShowIconsInMenus);
|
||||
#endif
|
||||
|
||||
// parse the command-line arguments
|
||||
int c = 0;
|
||||
bool minimized = false;
|
||||
char const* optarg = nullptr;
|
||||
QString host;
|
||||
QString port;
|
||||
QString username;
|
||||
QString password;
|
||||
QString config_dir;
|
||||
QStringList filenames;
|
||||
|
||||
while ((c = tr_getopt(getUsage(), argc, const_cast<char const**>(argv), Opts.data(), &optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'g':
|
||||
config_dir = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
port = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
host = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
username = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
password = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
minimized = true;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
qInfo() << qPrintable(display_name_) << LONG_VERSION_STRING;
|
||||
quitLater();
|
||||
return;
|
||||
|
||||
case TR_OPT_ERR:
|
||||
qWarning() << qPrintable(QObject::tr("Invalid option"));
|
||||
tr_getopt_usage(qPrintable(display_name_), getUsage(), Opts.data());
|
||||
quitLater();
|
||||
return;
|
||||
|
||||
default:
|
||||
filenames.append(QString::fromUtf8(optarg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// try to delegate the work to an existing copy of Transmission
|
||||
// before starting ourselves...
|
||||
InteropHelper const interop_client;
|
||||
|
||||
if (interop_client.isConnected())
|
||||
{
|
||||
bool delegated = false;
|
||||
|
||||
for (QString const& filename : filenames)
|
||||
{
|
||||
auto const a = AddData(filename);
|
||||
QString metainfo;
|
||||
|
||||
switch (a.type)
|
||||
{
|
||||
case AddData::URL:
|
||||
metainfo = a.url.toString();
|
||||
break;
|
||||
|
||||
case AddData::MAGNET:
|
||||
metainfo = a.magnet;
|
||||
break;
|
||||
|
||||
case AddData::FILENAME:
|
||||
case AddData::METAINFO:
|
||||
metainfo = QString::fromUtf8(a.toBase64());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!metainfo.isEmpty() && interop_client.addMetainfo(metainfo))
|
||||
{
|
||||
delegated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (delegated)
|
||||
{
|
||||
quitLater();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set the fallback config dir
|
||||
if (config_dir.isNull())
|
||||
{
|
||||
config_dir = QString::fromStdString(tr_getDefaultConfigDir("transmission"));
|
||||
}
|
||||
|
||||
// ensure our config directory exists
|
||||
QDir const dir(config_dir);
|
||||
|
||||
|
@ -258,45 +134,6 @@ Application::Application(int& argc, char** argv)
|
|||
// is this the first time we've run transmission?
|
||||
bool const first_time = !dir.exists(QStringLiteral("settings.json"));
|
||||
|
||||
// initialize the prefs
|
||||
prefs_ = std::make_unique<Prefs>(config_dir);
|
||||
|
||||
if (!host.isNull())
|
||||
{
|
||||
prefs_->set(Prefs::SESSION_REMOTE_HOST, host);
|
||||
}
|
||||
|
||||
if (!port.isNull())
|
||||
{
|
||||
prefs_->set(Prefs::SESSION_REMOTE_PORT, port.toUInt());
|
||||
}
|
||||
|
||||
if (!username.isNull())
|
||||
{
|
||||
prefs_->set(Prefs::SESSION_REMOTE_USERNAME, username);
|
||||
}
|
||||
|
||||
if (!password.isNull())
|
||||
{
|
||||
prefs_->set(Prefs::SESSION_REMOTE_PASSWORD, password);
|
||||
}
|
||||
|
||||
if (!host.isNull() || !port.isNull() || !username.isNull() || !password.isNull())
|
||||
{
|
||||
prefs_->set(Prefs::SESSION_IS_REMOTE, true);
|
||||
}
|
||||
|
||||
if (prefs_->getBool(Prefs::START_MINIMIZED))
|
||||
{
|
||||
minimized = true;
|
||||
}
|
||||
|
||||
// start as minimized only if the system tray present
|
||||
if (!prefs_->getBool(Prefs::SHOW_TRAY_ICON))
|
||||
{
|
||||
minimized = false;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(accessibility)
|
||||
QAccessible::installFactory(&accessibleFactory);
|
||||
#endif
|
||||
|
@ -395,6 +232,8 @@ Application::Application(int& argc, char** argv)
|
|||
#endif
|
||||
}
|
||||
|
||||
Application::~Application() = default;
|
||||
|
||||
void Application::loadTranslations()
|
||||
{
|
||||
auto const qt_qm_dirs = QStringList{} <<
|
||||
|
@ -425,8 +264,8 @@ void Application::loadTranslations()
|
|||
installTranslator(&qt_translator_);
|
||||
}
|
||||
|
||||
if (loadTranslation(app_translator_, config_name_, locale, app_qm_dirs) ||
|
||||
loadTranslation(app_translator_, config_name_, english_locale, app_qm_dirs))
|
||||
if (loadTranslation(app_translator_, ConfigName, locale, app_qm_dirs) ||
|
||||
loadTranslation(app_translator_, ConfigName, english_locale, app_qm_dirs))
|
||||
{
|
||||
installTranslator(&app_translator_);
|
||||
}
|
||||
|
@ -707,19 +546,3 @@ void Application::onNotificationActionInvoked(quint32 /* notification_id */, QSt
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
int tr_main(int argc, char** argv)
|
||||
{
|
||||
auto const init_mgr = tr_lib_init();
|
||||
|
||||
tr_locale_set_global("");
|
||||
|
||||
InteropHelper::initialize();
|
||||
|
||||
Application const app(argc, argv);
|
||||
return QApplication::exec();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,14 @@ class Application : public QApplication
|
|||
TR_DISABLE_COPY_MOVE(Application)
|
||||
|
||||
public:
|
||||
Application(int& argc, char** argv);
|
||||
Application(
|
||||
std::unique_ptr<Prefs> prefs,
|
||||
bool minimized,
|
||||
QString const& config_dir,
|
||||
QStringList const& filenames,
|
||||
int& argc,
|
||||
char** argv);
|
||||
~Application() override;
|
||||
|
||||
void raise() const;
|
||||
bool notifyApp(QString const& title, QString const& body, QStringList const& actions = {}) const;
|
||||
|
@ -113,9 +120,6 @@ private:
|
|||
|
||||
FaviconCache<QPixmap> favicon_cache_;
|
||||
|
||||
QString const config_name_ = QStringLiteral("transmission");
|
||||
QString const display_name_ = QStringLiteral("transmission-qt");
|
||||
|
||||
#ifdef QT_DBUS_LIB
|
||||
QString const fdo_notifications_service_name_ = QStringLiteral("org.freedesktop.Notifications");
|
||||
QString const fdo_notifications_path_ = QStringLiteral("/org/freedesktop/Notifications");
|
||||
|
|
|
@ -56,6 +56,7 @@ target_sources(${TR_NAME}-qt
|
|||
InteropObject.h
|
||||
LicenseDialog.cc
|
||||
LicenseDialog.h
|
||||
main.cc
|
||||
MainWindow.cc
|
||||
MainWindow.h
|
||||
MakeDialog.cc
|
||||
|
|
247
qt/main.cc
Normal file
247
qt/main.cc
Normal file
|
@ -0,0 +1,247 @@
|
|||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
|
||||
#include <libtransmission/tr-getopt.h>
|
||||
#include <libtransmission/utils.h>
|
||||
#include <libtransmission/version.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InteropHelper.h"
|
||||
#include "Prefs.h"
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
char const* const DisplayName = "transmission-qt";
|
||||
|
||||
auto constexpr FileArgsSeparator = "--"sv;
|
||||
auto constexpr QtArgsSeparator = "---"sv;
|
||||
|
||||
std::array<tr_option, 8> const Opts = {
|
||||
tr_option{ 'g', "config-dir", "Where to look for configuration files", "g", true, "<path>" },
|
||||
{ 'm', "minimized", "Start minimized in system tray", "m", false, nullptr },
|
||||
{ 'p', "port", "Port to use when connecting to an existing session", "p", true, "<port>" },
|
||||
{ 'r', "remote", "Connect to an existing session at the specified hostname", "r", true, "<host>" },
|
||||
{ 'u', "username", "Username to use when connecting to an existing session", "u", true, "<username>" },
|
||||
{ 'v', "version", "Show version number and exit", "v", false, nullptr },
|
||||
{ 'w', "password", "Password to use when connecting to an existing session", "w", true, "<password>" },
|
||||
{ 0, nullptr, nullptr, nullptr, false, nullptr }
|
||||
};
|
||||
|
||||
char const* getUsage()
|
||||
{
|
||||
return "Usage:\n"
|
||||
" transmission-qt [options...] [[--] torrent files...] [--- Qt options...]";
|
||||
}
|
||||
|
||||
bool tryDelegate(QStringList const& filenames)
|
||||
{
|
||||
InteropHelper const interop_client;
|
||||
if (!interop_client.isConnected())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool delegated = false;
|
||||
|
||||
for (auto const& filename : filenames)
|
||||
{
|
||||
auto const add_data = AddData(filename);
|
||||
QString metainfo;
|
||||
|
||||
switch (add_data.type)
|
||||
{
|
||||
case AddData::URL:
|
||||
metainfo = add_data.url.toString();
|
||||
break;
|
||||
|
||||
case AddData::MAGNET:
|
||||
metainfo = add_data.magnet;
|
||||
break;
|
||||
|
||||
case AddData::FILENAME:
|
||||
case AddData::METAINFO:
|
||||
metainfo = QString::fromUtf8(add_data.toBase64());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!metainfo.isEmpty() && interop_client.addMetainfo(metainfo))
|
||||
{
|
||||
delegated = true;
|
||||
}
|
||||
}
|
||||
|
||||
return delegated;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int tr_main(int argc, char** argv)
|
||||
{
|
||||
auto const init_mgr = tr_lib_init();
|
||||
|
||||
tr_locale_set_global("");
|
||||
|
||||
// parse the command-line arguments
|
||||
bool minimized = false;
|
||||
QString host;
|
||||
QString port;
|
||||
QString username;
|
||||
QString password;
|
||||
QString config_dir;
|
||||
QStringList filenames;
|
||||
|
||||
int opt = 0;
|
||||
char const* optarg = nullptr;
|
||||
int file_args_start_idx = -1;
|
||||
int qt_args_start_idx = -1;
|
||||
while (file_args_start_idx < 0 && qt_args_start_idx < 0 &&
|
||||
(opt = tr_getopt(getUsage(), argc, static_cast<char const* const*>(argv), std::data(Opts), &optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'g':
|
||||
config_dir = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
port = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
host = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
username = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
password = QString::fromUtf8(optarg);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
minimized = true;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
fmt::print("{:s} {:s}\n", DisplayName, LONG_VERSION_STRING);
|
||||
return 0;
|
||||
|
||||
case TR_OPT_ERR:
|
||||
fmt::print(stderr, "Invalid option\n");
|
||||
tr_getopt_usage(DisplayName, getUsage(), std::data(Opts));
|
||||
return 1;
|
||||
|
||||
default:
|
||||
if (optarg == FileArgsSeparator)
|
||||
{
|
||||
file_args_start_idx = tr_optind;
|
||||
}
|
||||
else if (optarg == QtArgsSeparator)
|
||||
{
|
||||
qt_args_start_idx = tr_optind;
|
||||
}
|
||||
else
|
||||
{
|
||||
filenames.append(QString::fromUtf8(optarg));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_args_start_idx >= 0)
|
||||
{
|
||||
for (int i = file_args_start_idx; i < argc; ++i)
|
||||
{
|
||||
if (argv[i] == QtArgsSeparator)
|
||||
{
|
||||
qt_args_start_idx = i + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
filenames.push_back(QString::fromUtf8(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
InteropHelper::initialize();
|
||||
|
||||
// try to delegate the work to an existing copy of Transmission
|
||||
// before starting ourselves...
|
||||
if (tryDelegate(filenames))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set the fallback config dir
|
||||
if (config_dir.isNull())
|
||||
{
|
||||
config_dir = QString::fromStdString(tr_getDefaultConfigDir("transmission"));
|
||||
}
|
||||
|
||||
// initialize the prefs
|
||||
auto prefs = std::make_unique<Prefs>(config_dir);
|
||||
|
||||
if (!host.isNull())
|
||||
{
|
||||
prefs->set(Prefs::SESSION_REMOTE_HOST, host);
|
||||
}
|
||||
|
||||
if (!port.isNull())
|
||||
{
|
||||
prefs->set(Prefs::SESSION_REMOTE_PORT, port.toUInt());
|
||||
}
|
||||
|
||||
if (!username.isNull())
|
||||
{
|
||||
prefs->set(Prefs::SESSION_REMOTE_USERNAME, username);
|
||||
}
|
||||
|
||||
if (!password.isNull())
|
||||
{
|
||||
prefs->set(Prefs::SESSION_REMOTE_PASSWORD, password);
|
||||
}
|
||||
|
||||
if (!host.isNull() || !port.isNull() || !username.isNull() || !password.isNull())
|
||||
{
|
||||
prefs->set(Prefs::SESSION_IS_REMOTE, true);
|
||||
}
|
||||
|
||||
if (prefs->getBool(Prefs::START_MINIMIZED))
|
||||
{
|
||||
minimized = true;
|
||||
}
|
||||
|
||||
// start as minimized only if the system tray present
|
||||
if (!prefs->getBool(Prefs::SHOW_TRAY_ICON))
|
||||
{
|
||||
minimized = false;
|
||||
}
|
||||
|
||||
auto qt_argv = std::vector<char*>{ argv[0] };
|
||||
if (qt_args_start_idx >= 0)
|
||||
{
|
||||
qt_argv.insert(qt_argv.end(), &argv[qt_args_start_idx], &argv[argc]);
|
||||
}
|
||||
|
||||
auto qt_argc = static_cast<int>(std::size(qt_argv));
|
||||
|
||||
Application const app(std::move(prefs), minimized, config_dir, filenames, qt_argc, std::data(qt_argv));
|
||||
return QApplication::exec();
|
||||
}
|
Loading…
Reference in a new issue