diff options
Diffstat (limited to '')
| -rw-r--r-- | TODO.org | 10 | ||||
| -rw-r--r-- | lua/api.lua | 2 | ||||
| -rw-r--r-- | src/InstanceManager.cpp | 106 | ||||
| -rw-r--r-- | src/InstanceManager.hpp | 39 | ||||
| -rw-r--r-- | src/LuaRuntime.hpp | 4 | ||||
| -rw-r--r-- | src/WindowActionRouter.hpp | 1 | ||||
| -rw-r--r-- | src/main.cpp | 54 | ||||
| -rw-r--r-- | src/widgets/BrowserApp.cpp | 6 | ||||
| -rw-r--r-- | src/widgets/BrowserApp.hpp | 2 | ||||
| -rw-r--r-- | src/widgets/BrowserWindow.cpp | 16 | ||||
| -rw-r--r-- | src/widgets/BrowserWindow.hpp | 2 |
11 files changed, 215 insertions, 27 deletions
@@ -11,21 +11,21 @@ - [X] Assign ID to each tab (reference in lua api) - [X] Tab select by id - [X] Multi-window -- [ ] New window on new window request -- [ ] Socket for opening window in current session (lua eval) +- [X] New window on new window request +- [X] Socket for opening window in current session (lua eval) +- [ ] Config loading and lua path - [ ] Events/autocommands - [ ] History storage - [ ] History completion - [ ] Log stdout, errors and results from lua somewhere -- [ ] Handle resource cleanup + signal disconnecting +- [ ] Downloading ** Next -- [ ] Config loading and runtime path - [ ] Conflict in keymap (keymap already exists) - [ ] Open url sanitize/humanize (add protocol if missing, remove quotes, etc) - [ ] Bookmarking -- [ ] Downloading - [ ] Get static linking for qt and libluv working +- [ ] Handle resource cleanup + signal disconnecting ** Later - [ ] Support multiple modes for keymap.set: `web.keymap.set({'n','i'}, ...)` diff --git a/lua/api.lua b/lua/api.lua index d078d72..b6495e0 100644 --- a/lua/api.lua +++ b/lua/api.lua @@ -7,7 +7,7 @@ end web.event.add_listener = function(events, opts) opts = shallow_copy(opts or {}) if type(events) ~= "table" then events = { events } end - opts.events = events + opts.events = events or {} __internals.register_event(opts) end diff --git a/src/InstanceManager.cpp b/src/InstanceManager.cpp new file mode 100644 index 0000000..4fb27f9 --- /dev/null +++ b/src/InstanceManager.cpp @@ -0,0 +1,106 @@ +#include <QLocalSocket> +#include <QtCore> +#include <cstdlib> +#include <qnamespace.h> + +#include "InstanceManager.hpp" + +InstanceManager::InstanceManager() { + bool connected = try_server_connection(); + if (!connected) { + server_init(); + } +} + +void InstanceManager::write_open_urls_to_socket(const QStringList &urls) { + if (socket == nullptr) + return; + + auto message = urls.join(" ").toStdString(); + socket->write(message.c_str()); + socket->write("\n"); +} + +void InstanceManager::write_lua_expr_to_socket(const QString &lua_expr) { + if (socket == nullptr) + return; + + auto message = ("lua " + lua_expr).toStdString(); + socket->write(message.c_str()); + socket->write("\n"); +} + +void InstanceManager::server_init() { + server = new QLocalServer(this); + is_server_mode = true; + + connect(server, &QLocalServer::newConnection, this, + &InstanceManager::handle_new_connection); + + QLocalServer::removeServer(socket_path); + if (!server->listen(socket_path)) { + qCritical() << "Unable to start server:" << server->serverError(); + exit(1); // TODO: Do something else? + } +} + +void InstanceManager::send_message() { + socket->waitForBytesWritten(); + socket->close(); +} + +void InstanceManager::handle_new_connection() { + if (!server->hasPendingConnections()) + return; + + qDebug() << "New connection"; + auto *client = server->nextPendingConnection(); + if (client == nullptr) + return; + + connect(client, &QLocalSocket::disconnected, client, + &QLocalSocket::deleteLater); + + client->waitForReadyRead(); + while (client->canReadLine()) { + QString data = client->readLine(); + + qDebug() << "RECV:" << data; + if (data.startsWith("lua ")) { + auto lua_expr = data.sliced(4); + emit lua_eval_requested(lua_expr); + } else { + QRegularExpression whitespace("\\s+"); + auto urls = data.split(whitespace, Qt::SkipEmptyParts); + emit urls_open_requested(urls); + } + } + + client->close(); +} + +bool InstanceManager::try_server_connection() { + socket = new QLocalSocket(this); + socket->connectToServer(socket_path); + + auto connected = socket->waitForConnected(200); + if (connected) + return true; + + socket->close(); + socket->deleteLater(); + socket = nullptr; + return false; +} + +InstanceManager::~InstanceManager() { + if (socket) { + socket->disconnectFromServer(); + socket->close(); + socket->deleteLater(); + } + if (server) { + server->disconnect(); + server->deleteLater(); + } +} diff --git a/src/InstanceManager.hpp b/src/InstanceManager.hpp new file mode 100644 index 0000000..0ef6e08 --- /dev/null +++ b/src/InstanceManager.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <QLocalServer> +#include <QLocalSocket> +#include <QtCore> + +#include "utils.hpp" + +class InstanceManager : public QObject { + Q_OBJECT + +public: + InstanceManager(); + ~InstanceManager() override; + void write_open_urls_to_socket(const QStringList &urls); + void write_lua_expr_to_socket(const QString &lua_expr); + void send_message(); + + DEFINE_GETTER(is_server, is_server_mode) + +signals: + void lua_eval_requested(const QString &lua_expr); + void urls_open_requested(const QStringList &urls); + +private slots: + void handle_new_connection(); + +protected: + bool try_server_connection(); + void server_init(); + +private: + QLocalServer *server = nullptr; + QLocalSocket *socket = nullptr; + bool is_server_mode = false; + + // TODO: On windows, \\.\pipe\null-browser + const char *socket_path = "/tmp/null-browser-socket.sock"; +}; diff --git a/src/LuaRuntime.hpp b/src/LuaRuntime.hpp index 074b76a..74b7810 100644 --- a/src/LuaRuntime.hpp +++ b/src/LuaRuntime.hpp @@ -74,11 +74,11 @@ private: public: static void inspect_lua_stack(lua_State *state) { int top = lua_gettop(state); - qDebug() << "Lua Stack (top: " << top << "):\n"; + qDebug() << "--- Lua Stack (top: " << top << ") ---\n"; for (int i = 1; i <= top; i++) { int type = lua_type(state, i); - qDebug() << i << ": " << lua_typename(state, type); + qDebug() << " " << i << ": " << lua_typename(state, type); } qDebug() << "---------------------------\n"; diff --git a/src/WindowActionRouter.hpp b/src/WindowActionRouter.hpp index 67bc681..7e9f5d3 100644 --- a/src/WindowActionRouter.hpp +++ b/src/WindowActionRouter.hpp @@ -54,6 +54,7 @@ private: uint64_t last_id = 1; Configuration *configuration; + // TODO: Split event handling to its own class std::mutex events_mutex; std::unordered_map<std::string, std::vector<EventHandlerRequest>> events; }; diff --git a/src/main.cpp b/src/main.cpp index d5ab486..ac0cedd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,61 @@ #include <QApplication> +#include "InstanceManager.hpp" +#include "LuaRuntime.hpp" +#include "WindowActionRouter.hpp" #include "widgets/BrowserApp.hpp" +QCommandLineParser *create_cli_parser() { + auto *parser = new QCommandLineParser(); + parser->setApplicationDescription("null-browser"); + parser->addHelpOption(); + parser->addVersionOption(); + parser->addPositionalArgument("url", "URL(s) to open", "[url]"); + parser->addOptions({ + {{"e", "expr"}, "Lua expression to execute", "lua"}, + }); + + return parser; +} + int main(int argc, char *argv[]) { const QApplication app(argc, argv); + QApplication::setApplicationName("null-browser"); + QApplication::setApplicationVersion("0.0.0"); + + auto *parser = create_cli_parser(); + parser->process(app); + + InstanceManager instance_manager; + if (instance_manager.is_server()) { + auto *browser = new BrowserApp; + browser->create_window(); + + auto &lua = LuaRuntime::instance(); + QObject::connect(&instance_manager, &InstanceManager::lua_eval_requested, + &lua, &LuaRuntime::evaluate); + QObject::connect(&instance_manager, &InstanceManager::urls_open_requested, + &lua, [browser](const QStringList &urls) { + qDebug() << urls; + browser->create_window(urls); + }); + } else { + qInfo() << "Using current instance"; + + auto urls = parser->positionalArguments(); + auto lua_expr = parser->value("expr"); + qDebug() << urls; + qDebug() << lua_expr; + + if (!urls.isEmpty() || lua_expr.isEmpty()) + instance_manager.write_open_urls_to_socket(urls); + + if (!lua_expr.isEmpty()) + instance_manager.write_lua_expr_to_socket(lua_expr); - BrowserApp browser; - browser.create_window(); - // browser.create_window(); + instance_manager.send_message(); + return 0; + } return QApplication::exec(); } diff --git a/src/widgets/BrowserApp.cpp b/src/widgets/BrowserApp.cpp index 2ab47c2..4977a2a 100644 --- a/src/widgets/BrowserApp.cpp +++ b/src/widgets/BrowserApp.cpp @@ -21,11 +21,11 @@ BrowserApp::BrowserApp() { lua.load_file("./config.lua"); connect(&window_action_router, &WindowActionRouter::new_window_requested, - this, [this](const QUrl &url) { create_window(url.toString()); }); + this, [this](const QUrl &url) { create_window({url.toString()}); }); }; -BrowserWindow *BrowserApp::create_window(const QString &url) { - auto *window = new BrowserWindow((const Configuration &)configuration, url); +BrowserWindow *BrowserApp::create_window(const QStringList &urls) { + auto *window = new BrowserWindow((const Configuration &)configuration, urls); window->setWindowTitle("null-browser"); WindowActionRouter::instance().add_window(window); window->show(); diff --git a/src/widgets/BrowserApp.hpp b/src/widgets/BrowserApp.hpp index b20d710..1b8fdcf 100644 --- a/src/widgets/BrowserApp.hpp +++ b/src/widgets/BrowserApp.hpp @@ -8,7 +8,7 @@ class BrowserApp : public QObject { public: BrowserApp(); - BrowserWindow *create_window(const QString &url = ""); + BrowserWindow *create_window(const QStringList &urls = {}); protected: bool eventFilter(QObject *target, QEvent *event) override; diff --git a/src/widgets/BrowserWindow.cpp b/src/widgets/BrowserWindow.cpp index 701167f..38392a0 100644 --- a/src/widgets/BrowserWindow.cpp +++ b/src/widgets/BrowserWindow.cpp @@ -11,7 +11,7 @@ #include "widgets/WebViewStack.hpp" BrowserWindow::BrowserWindow(const Configuration &configuration, - const QString &start_url) + const QStringList &urls) : configuration(configuration) { setCentralWidget(new QWidget()); @@ -50,17 +50,11 @@ BrowserWindow::BrowserWindow(const Configuration &configuration, } }); - // TODO: remove auto &lua = LuaRuntime::instance(); - lua.queue_task([this, start_url]() { - auto def_url = start_url.isEmpty() - ? "https://github.com/phenax/null-browser" - : start_url; - emit win_mediator->url_opened(def_url, OpenType::OpenUrlInTab, 0); - emit win_mediator->url_opened("https://ediblemonad.dev", - OpenType::OpenUrlInBgTab, 0); - emit win_mediator->url_opened("https://github.com/trending", - OpenType::OpenUrlInBgTab, 0); + lua.queue_task([this, urls]() { + for (const auto &url : urls) { + emit win_mediator->url_opened(url, OpenType::OpenUrlInTab, 0); + } }); } diff --git a/src/widgets/BrowserWindow.hpp b/src/widgets/BrowserWindow.hpp index db3c181..c83b4b7 100644 --- a/src/widgets/BrowserWindow.hpp +++ b/src/widgets/BrowserWindow.hpp @@ -13,7 +13,7 @@ class BrowserWindow : public QMainWindow { public: BrowserWindow(const Configuration &configuration, - const QString &start_url = ""); + const QStringList &urls = {}); DEFINE_GETTER(mediator, win_mediator) DEFINE_GETTER(get_id, win_id) |
