aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/LuaRuntime.cpp58
-rw-r--r--src/LuaRuntime.hpp36
-rw-r--r--src/WindowActionRouter.cpp37
-rw-r--r--src/WindowActionRouter.hpp10
-rw-r--r--src/events.hpp47
-rw-r--r--src/widgets/BrowserApp.cpp14
-rw-r--r--src/widgets/BrowserWindow.hpp3
7 files changed, 190 insertions, 15 deletions
diff --git a/src/LuaRuntime.cpp b/src/LuaRuntime.cpp
index 37349b0..f25b73b 100644
--- a/src/LuaRuntime.cpp
+++ b/src/LuaRuntime.cpp
@@ -1,4 +1,5 @@
#include "WindowActionRouter.hpp"
+#include "lua.h"
#include <QtCore>
#include <lua.hpp>
extern "C" {
@@ -11,6 +12,7 @@ extern "C" {
LuaRuntime::LuaRuntime() {
state = luaL_newstate();
luaL_openlibs(state);
+
preserve_top(state, { init_web_lib(); })
}
@@ -48,18 +50,12 @@ void LuaRuntime::evaluate(const QString &code) {
emit evaluation_failed(value);
} else {
const QVariant value = get_lua_value(-1);
- qDebug() << "result: " << value;
emit evaluation_completed(value);
}
})
});
}
-QVariant LuaRuntime::evaluate_sync(const QString &code) {
- luaL_dostring(state, code.toStdString().c_str());
- return get_lua_value(-1); // TODO: error handling
-}
-
void LuaRuntime::load_file(const QString &path) {
queue_task([this, path]() {
preserve_top(state, {
@@ -70,9 +66,59 @@ void LuaRuntime::load_file(const QString &path) {
});
}
+int LuaRuntime::lua_event_register(lua_State *state) {
+ EventHandlerRequest event;
+ auto top = lua_gettop(state);
+
+ lua_getfield(state, 1, "events");
+ auto event_names = LuaRuntime::lua_tostringlist(state);
+
+ event.event_names.swap(event_names);
+ if (event.event_names.size() == 0) {
+ lua_settop(state, top);
+ lua_pushboolean(state, false);
+ return 1;
+ }
+
+ lua_getfield(state, 1, "patterns");
+ auto patterns = LuaRuntime::lua_tostringlist(state);
+ event.patterns.swap(patterns);
+
+ lua_getfield(state, 1, "callback");
+ if (!lua_isfunction(state, -1)) {
+ lua_settop(state, top);
+ lua_pushboolean(state, false);
+ return 1;
+ }
+
+ const int function_ref = luaL_ref(state, LUA_REGISTRYINDEX);
+ event.function_ref = function_ref;
+ // TODO: Delete ref on clear callback
+ event.handler = [state, function_ref](BrowserEvent &event) {
+ preserve_top(state, {
+ lua_rawgeti(state, LUA_REGISTRYINDEX, function_ref);
+ event.lua_push(state);
+ lua_call(state, 1, 0);
+ })
+ };
+
+ WindowActionRouter::instance().register_event(event);
+
+ lua_settop(state, top);
+ lua_pushboolean(state, true);
+ return 1;
+}
+
void LuaRuntime::init_web_lib() {
// NOLINTBEGIN(modernize-avoid-c-arrays)
+ luaL_Reg internals[] = {
+ {"register_event", &LuaRuntime::lua_event_register},
+ {nullptr, nullptr},
+ };
+ luaL_newlib(state, internals);
+ lua_setglobal(state, internals_global_name);
+
// web
luaL_Reg web[] = {
/// @deprecated
diff --git a/src/LuaRuntime.hpp b/src/LuaRuntime.hpp
index d2211df..074b76a 100644
--- a/src/LuaRuntime.hpp
+++ b/src/LuaRuntime.hpp
@@ -3,8 +3,10 @@
#include <QtCore>
#include <functional>
#include <lua.hpp>
+#include <string>
#include "AsyncEventLoop.hpp"
+#include "lua.h"
#include "utils.hpp"
#include "widgets/WebViewStack.hpp"
@@ -18,6 +20,7 @@ class LuaRuntime : public QObject {
const char *uv_global_name = "uv";
const char *web_global_name = "web";
+ const char *internals_global_name = "__internals";
public:
static LuaRuntime &instance() {
@@ -27,7 +30,6 @@ public:
void evaluate(const QString &code);
void load_file(const QString &path);
- QVariant evaluate_sync(const QString &code);
void stop_event_loop();
void start_event_loop();
@@ -55,6 +57,7 @@ protected:
// Lua api
static int lua_history_back(lua_State *state);
static int lua_history_forward(lua_State *state);
+ static int lua_event_register(lua_State *state);
static int lua_keymap_set(lua_State *state);
static int lua_open_url(lua_State *state);
static int lua_tab_close(lua_State *state);
@@ -66,4 +69,35 @@ protected:
private:
lua_State *state;
AsyncEventLoop *event_loop = nullptr;
+
+ // TEMP
+public:
+ static void inspect_lua_stack(lua_State *state) {
+ int top = lua_gettop(state);
+ 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() << "---------------------------\n";
+ lua_settop(state, top);
+ }
+
+ static std::vector<std::string> lua_tostringlist(lua_State *state) {
+ std::vector<std::string> values;
+ if (!lua_istable(state, -1))
+ return values;
+
+ lua_pushnil(state); // First key for lua_next()
+ while (lua_next(state, -2) != 0) {
+ if (lua_isstring(state, -1))
+ values.emplace_back(lua_tostring(state, -1));
+ lua_pop(state, 1);
+ }
+ lua_pop(state, 1);
+
+ return values;
+ }
};
diff --git a/src/WindowActionRouter.cpp b/src/WindowActionRouter.cpp
index 1c5164e..89f92c7 100644
--- a/src/WindowActionRouter.cpp
+++ b/src/WindowActionRouter.cpp
@@ -1,12 +1,49 @@
#include <QWidget>
#include <QtCore>
+#include <string>
+#include <unordered_map>
#include "LuaRuntime.hpp"
#include "WindowActionRouter.hpp"
#include "keymap/KeymapEvaluator.hpp"
+#include "widgets/BrowserWindow.hpp"
#include "widgets/WebViewStack.hpp"
+void WindowActionRouter::dispatch_event(BrowserEvent &event) {
+ auto &runtime = LuaRuntime::instance();
+ runtime.queue_task([this, &event]() {
+ std::unordered_map<std::string, std::vector<EventHandlerRequest>> event_map;
+ {
+ const std::lock_guard<std::mutex> lock(events_mutex);
+ event_map = events;
+ }
+
+ if (!event_map.contains(event.kind))
+ return;
+
+ for (auto &event_handler : event_map.at(event.kind)) {
+ // TODO: Pattern filter
+ event_handler.handler(event);
+ }
+ });
+}
+
+void WindowActionRouter::register_event(const EventHandlerRequest &event) {
+ const std::lock_guard<std::mutex> lock(events_mutex);
+ for (const auto &event_name : event.event_names) {
+ if (!events.contains(event_name))
+ events.insert({event_name, {}});
+ events.at(event_name).emplace_back(event);
+ }
+}
+
void WindowActionRouter::initialize() {
+ UrlChangedEvent url_changed_event("https://googa.com", 2, 1);
+ WindowActionRouter::instance().dispatch_event(url_changed_event);
+
+ UrlChangedEvent url_changed_event_1("https://duckduckgo.com", 5, 1);
+ WindowActionRouter::instance().dispatch_event(url_changed_event_1);
+
auto &runtime = LuaRuntime::instance();
connect(&runtime, &LuaRuntime::keymap_added, this,
diff --git a/src/WindowActionRouter.hpp b/src/WindowActionRouter.hpp
index 384c76c..62aa65d 100644
--- a/src/WindowActionRouter.hpp
+++ b/src/WindowActionRouter.hpp
@@ -4,7 +4,11 @@
#include <QtCore>
#include <cstdint>
#include <functional>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include "events.hpp"
#include "widgets/BrowserWindow.hpp"
#include "widgets/WebViewStack.hpp"
@@ -33,6 +37,9 @@ public:
WebViewId fetch_current_tab_id(WindowId win_id = 0);
QList<WebViewData> fetch_webview_data_list(WindowId win_id = 0);
+ void dispatch_event(BrowserEvent &event);
+ void register_event(const EventHandlerRequest &event);
+
protected:
WindowActionRouter() = default;
@@ -42,4 +49,7 @@ protected:
private:
WindowMap window_map;
uint64_t last_id = 1;
+
+ std::mutex events_mutex;
+ std::unordered_map<std::string, std::vector<EventHandlerRequest>> events;
};
diff --git a/src/events.hpp b/src/events.hpp
new file mode 100644
index 0000000..6d10fc7
--- /dev/null
+++ b/src/events.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <QtCore>
+#include <lua.hpp>
+
+#include "lua.h"
+#include "widgets/BrowserWindow.hpp"
+#include "widgets/WebViewStack.hpp"
+
+#define SET_FIELD(NAME, TYPE, VALUE) \
+ lua_pushstring(state, NAME); \
+ lua_push##TYPE(state, VALUE); \
+ lua_settable(state, -3);
+
+class BrowserEvent {
+public:
+ std::string kind = "-";
+ virtual ~BrowserEvent() = default;
+
+ virtual void lua_push(lua_State *state) { lua_newtable(state); };
+};
+
+class UrlChangedEvent : public BrowserEvent {
+public:
+ const QString url;
+ const WebViewId webview_id;
+ const WindowId win_id;
+
+ UrlChangedEvent(QString url, WebViewId webview_id, WindowId win_id)
+ : url(std::move(url)), webview_id(webview_id), win_id(win_id) {
+ kind = "UrlChanged";
+ }
+
+ void lua_push(lua_State *state) override {
+ lua_newtable(state);
+ SET_FIELD("tab", integer, webview_id)
+ SET_FIELD("win", integer, win_id)
+ SET_FIELD("url", string, url.toStdString().c_str())
+ }
+};
+
+struct EventHandlerRequest {
+ std::vector<std::string> event_names;
+ std::vector<std::string> patterns;
+ std::function<void(BrowserEvent &)> handler;
+ int function_ref;
+};
diff --git a/src/widgets/BrowserApp.cpp b/src/widgets/BrowserApp.cpp
index f2d541d..d65a122 100644
--- a/src/widgets/BrowserApp.cpp
+++ b/src/widgets/BrowserApp.cpp
@@ -11,8 +11,7 @@ BrowserApp::BrowserApp() {
lua.start_event_loop();
// Router init
- auto &router = WindowActionRouter::instance();
- router.initialize();
+ WindowActionRouter::instance().initialize();
// Global event filter
qApp->installEventFilter(this);
@@ -22,14 +21,15 @@ BrowserApp::BrowserApp() {
};
BrowserWindow *BrowserApp::create_window() {
- auto *win = new BrowserWindow((const Configuration &)configuration);
- win->setWindowTitle("null-browser");
- WindowActionRouter::instance().add_window(win);
- win->show();
- return win;
+ auto *window = new BrowserWindow((const Configuration &)configuration);
+ window->setWindowTitle("null-browser");
+ WindowActionRouter::instance().add_window(window);
+ window->show();
+ return window;
}
bool BrowserApp::eventFilter(QObject *target, QEvent *event) {
+ // TODO: Prevent key release and shortcut on mode too
if (event->type() != QEvent::KeyPress)
return false;
diff --git a/src/widgets/BrowserWindow.hpp b/src/widgets/BrowserWindow.hpp
index 9aeeda3..4865ec9 100644
--- a/src/widgets/BrowserWindow.hpp
+++ b/src/widgets/BrowserWindow.hpp
@@ -6,7 +6,7 @@
#include "WindowMediator.hpp"
#include "utils.hpp"
-using WindowId = uint64_t;
+using WindowId = qsizetype;
class BrowserWindow : public QMainWindow {
Q_OBJECT
@@ -24,6 +24,7 @@ public:
signals:
void closed();
+ // void new_window_requested(const QUrl &url);
private:
WindowMediator *win_mediator;