diff options
-rw-r--r-- | data/poi.toml | 2 | ||||
-rw-r--r-- | smolbote.qbs | 2 | ||||
-rw-r--r-- | src/browser.cpp | 129 | ||||
-rw-r--r-- | src/browser.h | 20 | ||||
-rw-r--r-- | src/main.cpp | 29 | ||||
-rw-r--r-- | src/singleapplication.cpp | 71 | ||||
-rw-r--r-- | src/singleapplication.h | 51 | ||||
-rw-r--r-- | src/widgets/mainwindowmenubar.cpp | 4 |
8 files changed, 210 insertions, 98 deletions
diff --git a/data/poi.toml b/data/poi.toml index e2f37e6..34fb697 100644 --- a/data/poi.toml +++ b/data/poi.toml @@ -12,8 +12,6 @@ search="https://duckduckgo.com/?q=$term&kp=-1" # Browser: application-wide settings [browser] -singleInstance=true -localSocket="smolbote-singlelock" #sessionPath="$cache/session.json" # Profile diff --git a/smolbote.qbs b/smolbote.qbs index 60bd062..074b44b 100644 --- a/smolbote.qbs +++ b/smolbote.qbs @@ -60,6 +60,8 @@ Project { "src/browser.h", "src/interfaces.h", "src/main.cpp", + "src/singleapplication.cpp", + "src/singleapplication.h", ] cpp.defines: { if(project.deprecatedWarnings) diff --git a/src/browser.cpp b/src/browser.cpp index f95d01a..ce36123 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -28,10 +28,9 @@ #include "interfaces.h" Browser::Browser(int &argc, char *argv[]) : - QApplication(argc, argv) + SingleApplication(argc, argv) { m_settings = nullptr; - m_localServer = nullptr; m_networkAccessManager = nullptr; m_urlRequestInterceptor = nullptr; @@ -40,6 +39,13 @@ Browser::Browser(int &argc, char *argv[]) : m_blocklistManager = nullptr; m_plugin = nullptr; + + setApplicationName("smolbote"); +#ifdef GIT_VERSION + setApplicationVersion(GIT_VERSION); +#else + setApplicationVersion("1.0.0"); +#endif } Browser::~Browser() @@ -69,51 +75,8 @@ QString Browser::applicationLongVersion() const #endif } -bool Browser::prepare(QStringList urls) +void Browser::loadPlugins() { - if(m_settings->value("browser.singleInstance", true).toBool()) { - QString serverName = m_settings->value("browser.localSocket", "smolbote-singlelock").toString(); - - // Check for other running instance - QLocalSocket socket; - socket.connectToServer(serverName); - if(socket.waitForConnected(500)) { - QTextStream stream(&socket); - stream << urls.join('|'); - stream.flush(); - socket.waitForBytesWritten(); - return false; - } - - // There is no other instance - m_localServer = new QLocalServer(this); - connect(m_localServer, SIGNAL(newConnection()), this, SLOT(handleNewConnection())); - if (!m_localServer->listen(serverName) && m_localServer->serverError() == QAbstractSocket::AddressInUseError) { - // Could not create local server because the socket is already in use - QLocalServer::removeServer(serverName); - if (!m_localServer->listen(serverName)) { - // Couldn't free the socket - qWarning("Could not create local socket %s.", qPrintable(serverName)); - } - } else { - qDebug("Created local socket."); - } - } - - if(m_settings->isEmpty()) { - // There are no keys in the settings - QMessageBox::information(0, - tr("Configuration is empty"), - tr("The configuration file <i>%1</i> is empty. Using default values").arg(m_settings->filePath())); - } - - m_networkAccessManager = new QNetworkAccessManager(); - m_bookmarksManager = new BookmarksWidget; - m_downloadManager = new DownloadsWidget; - m_blocklistManager = new BlockerManager; - - QtWebEngine::initialize(); - // Loading plugins qDebug(">> Looking for plugins..."); @@ -139,12 +102,13 @@ bool Browser::prepare(QStringList urls) } qDebug("<< Plugins end..."); +} +void Browser::loadProfiles() +{ // TODO properly profile(""); profile("Default"); - - return true; } Browser *Browser::instance() @@ -159,21 +123,33 @@ Settings *Browser::settings() QNetworkAccessManager *Browser::network() { + if(!m_networkAccessManager) { + m_networkAccessManager = new QNetworkAccessManager(); + } return m_networkAccessManager; } BookmarksWidget *Browser::bookmarks() { + if(!m_bookmarksManager) { + m_bookmarksManager = new BookmarksWidget(); + } return m_bookmarksManager; } DownloadsWidget *Browser::downloads() { + if(!m_downloadManager) { + m_downloadManager = new DownloadsWidget(); + } return m_downloadManager; } BlockerManager *Browser::blocklists() { + if(!m_blocklistManager) { + m_blocklistManager = new BlockerManager(); + } return m_blocklistManager; } @@ -203,6 +179,21 @@ void Browser::setConfigPath(const QString &path) else { m_settings = new Settings(); } + + if(m_settings->isEmpty()) { + // There are no keys in the settings + QMessageBox::information(0, + tr("Configuration is empty"), + tr("The configuration file <i>%1</i> is empty. Using default values").arg(m_settings->filePath())); + } +} + +MainWindow *Browser::mainWindow() +{ + if(m_windows.isEmpty()) { + addWindow(new MainWindow()); + } + return m_windows.first(); } void Browser::addWindow(MainWindow *window) @@ -219,12 +210,24 @@ void Browser::addWindow(MainWindow *window) window->show(); } -MainWindow *Browser::mainWindow() +void Browser::addWindow(const QStringList params) { - if(m_windows.isEmpty()) { - addWindow(new MainWindow()); + QString p; // get default profile + QStringList urls; + + for(int i = 0; i < params.length(); i++) { + if(params.at(i) == "-p" || params.at(i) == "--profile") { + i++; + p = params.at(i); + } else if(!params.at(i).startsWith('-')) { + urls.append(params.at(i)); + } } - return m_windows.first(); + + MainWindow *w = new MainWindow(urls); + w->setProfile(profile(p)); + + addWindow(w); } void Browser::removeWindow(MainWindow *window) @@ -244,7 +247,7 @@ WebEngineProfile* Browser::profile(const QString name) if(!m_urlRequestInterceptor) { m_urlRequestInterceptor = new UrlRequestInterceptor(this); - m_urlRequestInterceptor->setSubscription(m_blocklistManager); + m_urlRequestInterceptor->setSubscription(blocklists()); } m_profiles[name]->setRequestInterceptor(m_urlRequestInterceptor); @@ -264,25 +267,7 @@ QStringList Browser::profiles() return l; } -QObject *Browser::plugin() +QObject *Browser::plugin(const QString name) { return m_plugin; } - -void Browser::handleNewConnection() -{ - QLocalSocket *socket = m_localServer->nextPendingConnection(); - if(!socket) { - // null socket -> return - return; - } - - socket->waitForReadyRead(); - const QStringList urls = QString(socket->readAll()).split('|'); - delete socket; - - QStringList::const_iterator i; - for(i = urls.constBegin(); i != urls.constEnd(); ++i) { - mainWindow()->newTab(QUrl::fromUserInput(*i)); - } -} diff --git a/src/browser.h b/src/browser.h index 2c30bcc..75102c6 100644 --- a/src/browser.h +++ b/src/browser.h @@ -21,11 +21,10 @@ #ifndef BROWSER_H #define BROWSER_H -#include <QApplication> +#include "singleapplication.h" #include <QVector> #include "forms/bookmarkswidget.h" #include "forms/downloadswidget.h" -#include <QLocalServer> #include "settings.h" #include <QNetworkAccessManager> #include "webengine/webengineprofile.h" @@ -38,7 +37,7 @@ #define sNetwork Browser::instance()->network() class MainWindow; -class Browser : public QApplication +class Browser : public SingleApplication { Q_OBJECT @@ -48,7 +47,9 @@ public: QString applicationLongVersion() const; - bool prepare(QStringList urls); + void setConfigPath(const QString &path); + void loadPlugins(); + void loadProfiles(); static Browser *instance(); @@ -58,24 +59,21 @@ public: DownloadsWidget *downloads(); BlockerManager *blocklists(); - void setConfigPath(const QString &path); - void addWindow(MainWindow* window); MainWindow *mainWindow(); WebEngineProfile *profile(const QString name); QStringList profiles(); - QObject *plugin(); + QObject *plugin(const QString name); + QStringList plugins(); public slots: + void addWindow(MainWindow* window); + void addWindow(const QStringList params); void removeWindow(MainWindow* window); -private slots: - void handleNewConnection(); - private: Settings *m_settings; - QLocalServer *m_localServer; QVector<MainWindow *> m_windows; QHash<QString, WebEngineProfile *> m_profiles; diff --git a/src/main.cpp b/src/main.cpp index e1f4c5c..bf4c29f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,15 +26,10 @@ int main(int argc, char *argv[]) { Browser app(argc, argv); - app.setApplicationName("smolbote"); -#ifdef GIT_VERSION - app.setApplicationVersion(GIT_VERSION); -#else - app.setApplicationVersion("1.0.0"); -#endif - app.setWindowIcon(QIcon(QLatin1String(":/icon.svg"))); - // This lets the web view automatically scale on high-dpi displays. - app.setAttribute(Qt::AA_EnableHighDpiScaling); + if(app.isRunning()) { + qDebug("Another instance is running, returning..."); + return 0; + } QCommandLineParser parser; parser.setApplicationDescription("yet another Qt browser"); @@ -45,12 +40,24 @@ int main(int argc, char *argv[]) parser.addOption(configOption); QCommandLineOption profileOption(QStringList() << "p" << "profile", "Use this profile.", "PROFILE"); parser.addOption(profileOption); + QCommandLineOption nopluginsOption(QStringList() << "n" << "noplugins", "Don't load plugins"); + parser.addOption(nopluginsOption); parser.process(app); + + app.setWindowIcon(QIcon(QLatin1String(":/icon.svg"))); + // This lets the web view automatically scale on high-dpi displays. + app.setAttribute(Qt::AA_EnableHighDpiScaling); + + // Set configuration app.setConfigPath(parser.value(configOption)); - if(!app.prepare(parser.positionalArguments())) { - return 0; + // Load profiles + app.loadProfiles(); + + // Load plugins + if(!parser.isSet(nopluginsOption)) { + app.loadPlugins(); } MainWindow *w = new MainWindow(parser.positionalArguments()); diff --git a/src/singleapplication.cpp b/src/singleapplication.cpp new file mode 100644 index 0000000..3a23bfb --- /dev/null +++ b/src/singleapplication.cpp @@ -0,0 +1,71 @@ +/******************************************************************************* + ** + ** smolbote: yet another qute browser + ** Copyright (C) 2017 Xian Nox + ** + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program. If not, see <http://www.gnu.org/licenses/>. + ** + ******************************************************************************/ + +#include "singleapplication.h" +#include <QLocalSocket> + +SingleApplication::SingleApplication(int &argc, char **argv) : QApplication(argc, argv) +{ + m_localServer = new QLocalServer(this); + connect(m_localServer, SIGNAL(newConnection()), this, SLOT(receiveMessage())); + + // if we can't send the arguments to a listening local server, start one + if(!sendMessage(arguments())) { + // remove any unused socket + QLocalServer::removeServer(LOCALSERVER_KEY); + if(!m_localServer->listen(LOCALSERVER_KEY)) { + qWarning("Cannot bind local server [%s]", qUtf8Printable(LOCALSERVER_KEY)); + } + } + +} + +bool SingleApplication::isRunning() +{ + return !m_localServer->isListening(); +} + +bool SingleApplication::sendMessage(const QStringList ¶ms) +{ + QLocalSocket socket; + socket.connectToServer(LOCALSERVER_KEY); + if(socket.waitForConnected(LOCALSERVER_TIMEOUT)) { + socket.write(params.join('|').toUtf8()); + socket.waitForBytesWritten(); + return true; + } + + return false; +} + +void SingleApplication::receiveMessage() +{ + QLocalSocket *socket = m_localServer->nextPendingConnection(); + if(!socket) { + // null socket --> return + return; + } + + socket->waitForReadyRead(); + const QStringList params = QString(socket->readAll()).split('|'); + socket->deleteLater(); + + emit messageAvailable(params); +} diff --git a/src/singleapplication.h b/src/singleapplication.h new file mode 100644 index 0000000..7b1fce9 --- /dev/null +++ b/src/singleapplication.h @@ -0,0 +1,51 @@ +/******************************************************************************* + ** + ** smolbote: yet another qute browser + ** Copyright (C) 2017 Xian Nox + ** + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 3 of the License, or + ** (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with this program. If not, see <http://www.gnu.org/licenses/>. + ** + ******************************************************************************/ + +#ifndef SINGLEAPPLICATION_H +#define SINGLEAPPLICATION_H + +#include <QApplication> +#include <QLocalServer> +#include <QVector> +#include <QUrl> + +class SingleApplication : public QApplication +{ + Q_OBJECT +public: + explicit SingleApplication(int &argc, char **argv); + + bool isRunning(); + bool sendMessage(const QStringList ¶ms); + +signals: + void messageAvailable(const QStringList params); + +private slots: + void receiveMessage(); + +private: + const int LOCALSERVER_TIMEOUT = 500; + const QString LOCALSERVER_KEY = "smolbote_KEY"; + + QLocalServer *m_localServer; +}; + +#endif // SINGLEAPPLICATION_H diff --git a/src/widgets/mainwindowmenubar.cpp b/src/widgets/mainwindowmenubar.cpp index cd27a98..4ad9d67 100644 --- a/src/widgets/mainwindowmenubar.cpp +++ b/src/widgets/mainwindowmenubar.cpp @@ -54,8 +54,8 @@ MainWindowMenuBar::MainWindowMenuBar(MainWindow *parent) : toolsMenu->addSeparator(); toolsMenu->addAction(tr("Filter"), qApp->blocklists(), SLOT(show()), QKeySequence::fromString(sSettings->value("blocker.shortcut").toString())); - if(qApp->plugin()) { - GuiInterface *gui = qobject_cast<GuiInterface *>(qApp->plugin()); + if(qApp->plugin("")) { + GuiInterface *gui = qobject_cast<GuiInterface *>(qApp->plugin("")); if(gui) { toolsMenu->addAction(gui->action()); } else { |