aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/configuration/configuration.cpp7
-rw-r--r--lib/configuration/configuration.h12
-rw-r--r--plugins/interfaces.h2
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/browser.cpp115
-rw-r--r--src/browser.h14
-rw-r--r--src/main.cpp66
-rw-r--r--src/plugin.h93
8 files changed, 164 insertions, 147 deletions
diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp
index 6d8d1ba..e767c65 100644
--- a/lib/configuration/configuration.cpp
+++ b/lib/configuration/configuration.cpp
@@ -50,10 +50,7 @@ Configuration::Configuration()
("config,c", po::value<std::string>()->default_value(defaultUserConfigLocation()), "Set the configuration file.")
("socket,s", po::value<std::string>()->default_value(defaultSocketPath()), "Local server socket")
- ("command", po::value<std::string>(), "Run a plugin command.")
- ("commands", "List all plugin commands.")
-
- ("url", po::value<std::vector<std::string>>(), "URLs")
+ ("args", po::value<std::vector<std::string>>(), "arguments")
;
configuration_desc.add_options()
@@ -123,7 +120,7 @@ Configuration::Configuration()
("downloads.shortcut", po::value<std::string>()->default_value("Ctrl+D"))
;
- arguments_desc.add("url", -1);
+ arguments_desc.add("args", -1);
}
Configuration::~Configuration() = default;
diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h
index 59c837c..bb1b271 100644
--- a/lib/configuration/configuration.h
+++ b/lib/configuration/configuration.h
@@ -75,18 +75,6 @@ public:
return std::optional<T>(vm[path].as<T>());
}
- QStringList positionalArguments() const
- {
- QStringList l;
- if(vm.count("url")) {
- std::vector<std::string> urls = vm["url"].as<std::vector<std::string>>();
- for(const std::string &s : urls) {
- l.append(QString::fromStdString(s));
- }
- }
- return l;
- }
-
QHash<QString, QString> section(const std::string &prefix) const;
const boost::program_options::options_description commandlineOptions() const
{
diff --git a/plugins/interfaces.h b/plugins/interfaces.h
index 67cd3c6..1a12f02 100644
--- a/plugins/interfaces.h
+++ b/plugins/interfaces.h
@@ -24,7 +24,7 @@ struct Plugin
QString name;
QString author;
QKeySequence shortcut;
- std::shared_ptr<QObject> instance;
+ QObject *instance;
};
class PluginInterface
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 00b556f..5f4aed1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -43,7 +43,7 @@ add_executable(poi
webengine/widgets/pagemenu.h
# plugin interfaces
- #../plugins/interfaces.h
+ plugin.h
)
target_include_directories(poi
diff --git a/src/browser.cpp b/src/browser.cpp
index 29a02b7..f2c7314 100644
--- a/src/browser.cpp
+++ b/src/browser.cpp
@@ -24,64 +24,6 @@
#include <QJsonArray>
#include <about/aboutdialog.h>
-inline Plugin loadPluginFromPath(const QString &path)
-{
- Plugin p;
- QPluginLoader loader(path);
-
- if(loader.load()) {
-#ifdef QT_DEBUG
- qDebug("Loading plugin: %s [ok]", qUtf8Printable(path));
-#endif
-
- auto meta = loader.metaData().value("MetaData").toObject();
- p.name = meta.value("name").toString();
- p.author = meta.value("author").toString();
- p.shortcut = QKeySequence::fromString(meta.value("shortcut").toString());
-
- p.instance = std::shared_ptr<QObject>(loader.instance());
-
- } else {
- qDebug("Loading pluing: %s [failed]", qUtf8Printable(path));
- qDebug("%s", qUtf8Printable(loader.errorString()));
- }
-
- return p;
-}
-
-inline QVector<Plugin> loadPlugins(const QString &path)
-{
- QVector<Plugin> list;
- QFileInfo location(path);
- if(!location.exists()) {
- qDebug("Plugin location doesn't exist.");
- return list;
- }
-
- if(location.isFile()) {
- // only load this one plugin
- auto p = loadPluginFromPath(location.absoluteFilePath());
- if(p.instance)
- list.append(p);
-
- } else if(location.isDir()) {
- // load all profiles from this directory
- const auto entries = QDir(location.absoluteFilePath()).entryInfoList(QDir::Files | QDir::Readable);
- for(const auto &f : entries) {
- auto p = loadPluginFromPath(f.absoluteFilePath());
- if(p.instance)
- list.append(p);
- }
-
- } else {
-#ifdef QT_DEBUG
- qDebug("Path is neither file nor folder: %s", qUtf8Printable(path));
-#endif
- }
-
- return list;
-}
-
Browser::Browser(int &argc, char *argv[])
: SingleApplication(argc, argv)
{
@@ -96,10 +38,7 @@ Browser::~Browser()
m_bookmarks->save();
qDeleteAll(m_windows);
- m_windows.clear();
-
- //qDeleteAll(m_plugins);
- m_plugins.clear();
+ m_windows.clear();
}
@@ -118,31 +57,27 @@ void Browser::setConfiguration(std::shared_ptr<Configuration> &config)
m_config = config;
}
-void Browser::setup(const QString &defaultProfile)
+void Browser::registerPlugin(const Plugin &plugin)
{
- Q_ASSERT_X(m_config, "Browser::setup", "Configuration not set");
-
- // load plugins first
- m_plugins.append(loadPlugins(QString::fromStdString(m_config->value<std::string>("plugins.path").value())));
+ if(plugin.instance->inherits("ProfileInterface")) {
+ auto *profileEditor = qobject_cast<ProfileInterface *>(plugin.instance);
+ Q_ASSERT_X(profileEditor != nullptr, "Browser::setup", "profile interface cast failed");
- // register commands
- for(const Plugin &p : qAsConst(m_plugins)) {
-
- if(p.instance->inherits("ProfileInterface")) {
- auto *profileEditor = qobject_cast<ProfileInterface *>(p.instance.get());
- Q_ASSERT_X(profileEditor != nullptr, "Browser::setup", "profile interface cast failed");
-
- connect(this, &Browser::registerProfile, [=](WebProfile *profile) {
- profileEditor->registerProfile(profile);
- });
- }
-
- auto *plugin = qobject_cast<PluginInterface *>(p.instance.get());
- if(plugin) {
- m_commands.unite(plugin->commands());
+ for(auto it = m_profiles.constBegin(); it != m_profiles.constEnd(); ++it) {
+ profileEditor->registerProfile(it.value());
}
+ connect(this, &Browser::registerProfile, [=](WebProfile *profile) {
+ profileEditor->registerProfile(profile);
+ });
}
+ m_plugins.append(plugin);
+}
+
+void Browser::setup(const QString &defaultProfile)
+{
+ Q_ASSERT_X(m_config, "Browser::setup", "Configuration not set");
+
// load profiles
{
const auto defaults = m_config->section("profile");
@@ -203,16 +138,6 @@ WebProfile *Browser::profile(const QString &name) const
return nullptr;
}
-int Browser::command(const QString &command)
-{
- if(m_commands.contains(command)) {
- return m_commands.value(command)();
- } else {
- qWarning("No such command: %s", qUtf8Printable(command));
- return -1;
- }
-}
-
void Browser::createSession(const QString &profileName, bool newWindow, const QStringList &urls)
{
if(m_windows.isEmpty()) {
@@ -249,7 +174,7 @@ MainWindow *Browser::createWindow()
bookmarksAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value<std::string>("bookmarks.shortcut").value())));
connect(bookmarksAction, &QAction::triggered, window, [this, window]() {
bool wasVisible = m_bookmarks->isVisible();
- for(MainWindow *w : m_windows) {
+ for(MainWindow *w : qAsConst(m_windows)) {
w->removeDockWidget(m_bookmarks.get());
}
if(!wasVisible) {
@@ -262,7 +187,7 @@ MainWindow *Browser::createWindow()
downloadsAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value<std::string>("downloads.shortcut").value())));
connect(downloadsAction, &QAction::triggered, window, [this, window]() {
bool wasVisible = m_downloads->isVisible();
- for(MainWindow *w : m_windows) {
+ for(MainWindow *w : qAsConst(m_windows)) {
w->removeDockWidget(m_downloads.get());
}
if(!wasVisible) {
@@ -273,7 +198,7 @@ MainWindow *Browser::createWindow()
for(const Plugin &p : qAsConst(m_plugins)) {
if(p.instance->inherits("ProfileInterface")) {
- auto *profileEditor = qobject_cast<ProfileInterface *>(p.instance.get());
+ auto *profileEditor = qobject_cast<ProfileInterface *>(p.instance);
auto *profileAction = new QAction(tr("Profile"), window);
profileAction->setShortcut(p.shortcut);
connect(profileAction, &QAction::triggered, window, [profileEditor]() {
diff --git a/src/browser.h b/src/browser.h
index 7163c8f..821583a 100644
--- a/src/browser.h
+++ b/src/browser.h
@@ -38,6 +38,8 @@ public slots:
public:
void setConfiguration(std::shared_ptr<Configuration> &config);
+ void registerPlugin(const Plugin &plugin);
+
void setup(const QString &defaultProfile);
std::shared_ptr<BookmarksWidget> bookmarks()
@@ -51,17 +53,6 @@ public:
return m_profiles.keys();
}
- int command(const QString &command);
- const QStringList commands() const
- {
- return m_commands.keys();
- }
-
- const QVector<Plugin> plugins() const
- {
- return m_plugins;
- }
-
signals:
void registerProfile(WebProfile *profile);
@@ -78,7 +69,6 @@ private:
QMap<QString, WebProfile*> m_profiles;
QVector<MainWindow *> m_windows;
QVector<Plugin> m_plugins;
- QHash<QString, std::function<int()>> m_commands;
};
#endif // SMOLBOTE_BROWSER_H
diff --git a/src/main.cpp b/src/main.cpp
index c9b6007..c1060aa 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -12,24 +12,53 @@
#include <configuration/configuration.h>
#include <memory>
#include <iostream>
+#include "plugin.h"
int main(int argc, char **argv)
{
// create and load configuration
std::shared_ptr<Configuration> config = std::make_shared<Configuration>();
if(!config->parse(argc, argv)) {
- qWarning("Check --help for usage.");
+ qWarning("Error parsing command line, check --help for usage.");
return -1;
}
if(!config->parse(config->value<std::string>("config").value())) {
qWarning("Error parsing config file.");
}
+ // --version
+ if(config->exists("version")) {
+ std::cout << "smolbote " << SMOLBOTE_VERSION << std::endl;
+ return 0;
+ }
+
+ // --build
+ if(config->exists("build")) {
+ std::cout << SMOLBOTE_BRANCH << ":" << SMOLBOTE_COMMIT;
+ return 0;
+ }
+
+ QVector<Plugin> plugins = loadPlugins(config->value<QString>("plugins.path").value());
+ QHash<QString, std::function<int()>> pluginCommands;
+ for(const auto &plugin : plugins) {
+ auto *pluginInterface = qobject_cast<PluginInterface*>(plugin.instance);
+ Q_CHECK_PTR(pluginInterface);
+
+ pluginCommands.unite(pluginInterface->commands());
+ }
+
if(config->exists("help")) {
std::cout << "smolbote " << SMOLBOTE_VERSION << ": yet another no-frills browser" << std::endl;
- std::cout << "Usage: " << argv[0] << " [options] URL(s)" << std::endl << std::endl;
+ std::cout << "Usage: " << argv[0] << " [options] [command/URL(s)]" << std::endl << std::endl;
std::cout << "Command-line Options: " << std::endl << config->commandlineOptions() << std::endl;
+
+ std::cout << "Commands: " << std::endl;
+ for(auto it = pluginCommands.constBegin(); it != pluginCommands.constEnd(); ++it) {
+ std::cout << it.key().toStdString() << std::endl;
+ }
+ std::cout << std::endl;
+
std::cout << "Configuration Options: " << std::endl << config->configurationOptions() << std::endl;
#ifdef Q_OS_LINUX
@@ -38,32 +67,27 @@ int main(int argc, char **argv)
return 0;
}
- if(config->exists("version")) {
- std::cout << "smolbote " << SMOLBOTE_VERSION << std::endl;
- return 0;
- }
-
- if(config->exists("build")) {
- std::cout << SMOLBOTE_BRANCH << ":" << SMOLBOTE_COMMIT;
- return 0;
- }
-
Browser app(argc, argv);
// set this, otherwise the webview becomes black when using a stylesheet
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
app.setConfiguration(config);
app.setup(QString::fromStdString(config->value<std::string>("profile.default").value()));
-
- if(config->exists("commands")) {
- for(const QString &cmd : app.commands()) {
- std::cout << cmd.toStdString() << std::endl;
- }
- exit(0);
+ for(const Plugin &plugin : plugins) {
+ app.registerPlugin(plugin);
}
- if(config->exists("command")) {
- exit(app.command(QString::fromStdString(config->value<std::string>("command").value())));
+ auto arguments = config->value<std::vector<std::string>>("args");
+ QStringList urls;
+
+ if(arguments) {
+ for(const auto &u : arguments.value()) {
+ if(pluginCommands.contains(QString::fromStdString(u))) {
+ return pluginCommands.value(QString::fromStdString(u))();
+ } else {
+ urls.append(QString::fromStdString(u));
+ }
+ }
}
// set up socket
@@ -86,7 +110,7 @@ int main(int argc, char **argv)
QObject::connect(&app, &Browser::messageAvailable, &app, &Browser::createSession);
}
- app.sendMessage("", false, config->positionalArguments());
+ app.sendMessage("", false, urls);
if(isSingleInstance)
return app.exec();
else
diff --git a/src/plugin.h b/src/plugin.h
new file mode 100644
index 0000000..4de3407
--- /dev/null
+++ b/src/plugin.h
@@ -0,0 +1,93 @@
+/*
+ * This file is part of smolbote. It's copyrighted by the contributors recorded
+ * in the version control history of the file, available from its original
+ * location: https://neueland.iserlohn-fortress.net/smolbote.hg
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#ifndef SMOLBOTE_PLUGIN_H
+#define SMOLBOTE_PLUGIN_H
+
+#include <interfaces.h>
+#include <QPluginLoader>
+#include <QFileInfo>
+#include <QDir>
+
+inline Plugin loadPluginFromPath(const QString &path)
+{
+ Plugin p;
+ QPluginLoader loader(path);
+
+ if(loader.load()) {
+#ifdef QT_DEBUG
+ qDebug("Loading plugin: %s [ok]", qUtf8Printable(path));
+#endif
+
+ auto meta = loader.metaData().value("MetaData").toObject();
+ p.name = meta.value("name").toString();
+ p.author = meta.value("author").toString();
+ p.shortcut = QKeySequence::fromString(meta.value("shortcut").toString());
+
+ p.instance = loader.instance();
+
+ } else {
+ qDebug("Loading pluing: %s [failed]", qUtf8Printable(path));
+ qDebug("%s", qUtf8Printable(loader.errorString()));
+ }
+
+ return p;
+}
+
+inline QVector<Plugin> loadPlugins(const QString &path)
+{
+ QVector<Plugin> list;
+
+ // quit if there's nothing to load
+ if(path.isEmpty())
+ return list;
+
+ // plugins can be a semicolon-separated list
+ if(path.contains(';')) {
+ auto pluginList = path.split(';');
+ for(const auto &pluginPath : pluginList) {
+ auto plugin = loadPluginFromPath(pluginPath);
+ if(plugin.instance)
+ list.append(plugin);
+ }
+
+ return list;
+ }
+
+ // check if path is path to a file or a folder
+ QFileInfo location(path);
+
+ if(!location.exists()) {
+ qDebug("Plugin path doesn't exist.");
+ return list;
+ }
+
+ if(location.isFile()) {
+ // only load this one plugin
+ auto p = loadPluginFromPath(location.absoluteFilePath());
+ if(p.instance)
+ list.append(p);
+
+ } else if(location.isDir()) {
+ // load all profiles from this directory
+ const auto entries = QDir(location.absoluteFilePath()).entryInfoList(QDir::Files | QDir::Readable);
+ for(const auto &f : entries) {
+ auto p = loadPluginFromPath(f.absoluteFilePath());
+ if(p.instance)
+ list.append(p);
+ }
+#ifdef QT_DEBUG
+ } else {
+ qDebug("Path is neither file nor folder: %s", qUtf8Printable(path));
+#endif
+ }
+
+ return list;
+}
+
+#endif // SMOLBOTE_PLUGIN_H