diff options
| author | Akshay Nair <phenax5@gmail.com> | 2025-04-02 20:49:49 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2025-04-02 20:49:49 +0530 |
| commit | 96727d6e63ca927f3c7b68d4baa4fe672a4dcd0b (patch) | |
| tree | 2e5b99bb3324a35a0bd9ecdaa2caefcf9260767a /src | |
| parent | 4f945367ebc8e34263acbfca0416e3f75653924e (diff) | |
| download | null-browser-96727d6e63ca927f3c7b68d4baa4fe672a4dcd0b.tar.gz null-browser-96727d6e63ca927f3c7b68d4baa4fe672a4dcd0b.zip | |
Add events system for lua runtime to dispatch and register events
Diffstat (limited to '')
| -rw-r--r-- | src/LuaRuntime.cpp | 58 | ||||
| -rw-r--r-- | src/LuaRuntime.hpp | 36 | ||||
| -rw-r--r-- | src/WindowActionRouter.cpp | 37 | ||||
| -rw-r--r-- | src/WindowActionRouter.hpp | 10 | ||||
| -rw-r--r-- | src/events.hpp | 47 | ||||
| -rw-r--r-- | src/widgets/BrowserApp.cpp | 14 | ||||
| -rw-r--r-- | src/widgets/BrowserWindow.hpp | 3 |
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; |
