aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--TODO.org10
-rw-r--r--lua/api.lua2
-rw-r--r--src/InstanceManager.cpp106
-rw-r--r--src/InstanceManager.hpp39
-rw-r--r--src/LuaRuntime.hpp4
-rw-r--r--src/WindowActionRouter.hpp1
-rw-r--r--src/main.cpp54
-rw-r--r--src/widgets/BrowserApp.cpp6
-rw-r--r--src/widgets/BrowserApp.hpp2
-rw-r--r--src/widgets/BrowserWindow.cpp16
-rw-r--r--src/widgets/BrowserWindow.hpp2
11 files changed, 215 insertions, 27 deletions
diff --git a/TODO.org b/TODO.org
index bb9e51b..28573e3 100644
--- a/TODO.org
+++ b/TODO.org
@@ -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)