aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2025-03-25 13:13:02 +0530
committerAkshay Nair <phenax5@gmail.com>2025-03-25 18:20:18 +0530
commit4cbaaae7c55e71d2d4db591029394812077eb844 (patch)
tree23574a00f4790332e9aafb4fd86fbc046c0ed85a /src
parent346c16b4e2ea26f47e0e370a490b7794492a9ebb (diff)
downloadnull-browser-4cbaaae7c55e71d2d4db591029394812077eb844.tar.gz
null-browser-4cbaaae7c55e71d2d4db591029394812077eb844.zip
Add web.history for history navigation
Diffstat (limited to 'src')
-rw-r--r--src/AsyncEventLoop.cpp3
-rw-r--r--src/InputMediator.cpp44
-rw-r--r--src/InputMediator.hpp14
-rw-r--r--src/LuaRuntime.cpp64
-rw-r--r--src/LuaRuntime.hpp10
-rw-r--r--src/utils.hpp6
-rw-r--r--src/widgets/WebViewStack.cpp109
-rw-r--r--src/widgets/WebViewStack.hpp19
8 files changed, 177 insertions, 92 deletions
diff --git a/src/AsyncEventLoop.cpp b/src/AsyncEventLoop.cpp
index 3acbc41..0ee9986 100644
--- a/src/AsyncEventLoop.cpp
+++ b/src/AsyncEventLoop.cpp
@@ -31,6 +31,9 @@ void AsyncEventLoop::process_tasks() {
{
const std::lock_guard<std::mutex> lock(tasks_queue_mutex);
+ if (tasks_queue.empty())
+ return;
+
tasks_queue.swap(tasks);
}
diff --git a/src/InputMediator.cpp b/src/InputMediator.cpp
index aeb352b..1d86a2a 100644
--- a/src/InputMediator.cpp
+++ b/src/InputMediator.cpp
@@ -8,15 +8,23 @@
#include "widgets/WebViewStack.hpp"
// TODO: Rename this
-InputMediator::InputMediator(WebViewStack *web_view_stack,
+InputMediator::InputMediator(WebViewStack *webview_stack,
LuaRuntime *lua_runtime,
KeymapEvaluator *keymap_evaluator)
- : web_view_stack(web_view_stack), lua_runtime(lua_runtime),
+ : webview_stack(webview_stack), lua_runtime(lua_runtime),
keymap_evaluator(keymap_evaluator) {
- connect(lua_runtime, &LuaRuntime::url_opened, web_view_stack,
+ connect(lua_runtime, &LuaRuntime::url_opened, webview_stack,
&WebViewStack::open_url);
connect(lua_runtime, &LuaRuntime::keymap_add_requested, this,
&InputMediator::add_keymap);
+ connect(lua_runtime, &LuaRuntime::history_back_requested, webview_stack,
+ &WebViewStack::webview_history_back);
+ connect(lua_runtime, &LuaRuntime::history_forward_requested, webview_stack,
+ &WebViewStack::webview_history_forward);
+
+ lua_runtime->set_current_tab_id_fetcher([this]() {
+ return this->webview_stack->current_webview_index();
+ });
}
void InputMediator::add_keymap(const QString &mode_string,
@@ -26,32 +34,4 @@ void InputMediator::add_keymap(const QString &mode_string,
keymap_evaluator->add_keymap(mode, keyseq, std::move(action));
}
-// void InputMediator::evaluate_command(QString command) {
-// CommandParser parser;
-// auto cmd = parser.parse(command);
-//
-// switch (cmd.command) {
-// case CommandType::LuaEval:
-// lua_runtime->evaluate(cmd.argsString);
-// break;
-// case CommandType::Open:
-// open_url(cmd.argsString, OpenType::OpenUrl);
-// break;
-// case CommandType::TabOpen:
-// open_url(cmd.argsString, OpenType::OpenUrlInTab);
-// break;
-// case CommandType::TabNext:
-// next_web_view();
-// break;
-// case CommandType::TabPrev:
-// previous_web_view();
-// break;
-// case CommandType::TabSelect:
-// web_view_stack->focus_web_view(cmd.argsString.toLong());
-// break;
-// case CommandType::Noop:
-// break;
-// }
-// }
-
-InputMediator::~InputMediator() { delete web_view_stack; }
+InputMediator::~InputMediator() { delete webview_stack; }
diff --git a/src/InputMediator.hpp b/src/InputMediator.hpp
index 2cd34f2..5933bd7 100644
--- a/src/InputMediator.hpp
+++ b/src/InputMediator.hpp
@@ -12,15 +12,15 @@ class InputMediator : public QObject {
Q_OBJECT
public:
- InputMediator(WebViewStack *web_view_stack, LuaRuntime *lua_runtime,
+ InputMediator(WebViewStack *webview_stack, LuaRuntime *lua_runtime,
KeymapEvaluator *keymap_evaluator);
~InputMediator() override;
- DELEGATE(web_view_stack, open_url, open_url)
- DELEGATE(web_view_stack, current_url, current_url)
- DELEGATE(web_view_stack, next, next_web_view)
- DELEGATE(web_view_stack, previous, previous_web_view)
- DELEGATE(web_view_stack, close_current, close_current_web_view)
+ DELEGATE(webview_stack, open_url, open_url)
+ DELEGATE(webview_stack, current_url, current_url)
+ DELEGATE(webview_stack, next, next_webview)
+ DELEGATE(webview_stack, previous, previous_webview)
+ DELEGATE(webview_stack, close_current, close_current_webview)
DELEGATE(keymap_evaluator, evaluate, evaluate_keymap)
protected:
@@ -28,7 +28,7 @@ protected:
std::function<void()> action);
private:
- WebViewStack *web_view_stack;
+ WebViewStack *webview_stack;
LuaRuntime *lua_runtime;
KeymapEvaluator *keymap_evaluator;
};
diff --git a/src/LuaRuntime.cpp b/src/LuaRuntime.cpp
index eb61a19..0149e10 100644
--- a/src/LuaRuntime.cpp
+++ b/src/LuaRuntime.cpp
@@ -39,7 +39,7 @@ void LuaRuntime::stop_event_loop() {
}
void LuaRuntime::evaluate(const QString &code) {
- event_loop->queue_task([this, code]() {
+ queue_task([this, code]() {
preserve_top(state, {
if (luaL_dostring(state, code.toStdString().c_str()) != LUA_OK) {
const char *value = lua_tostring(state, -1);
@@ -59,7 +59,10 @@ QVariant LuaRuntime::evaluate_sync(const QString &code) {
return get_lua_value(-1); // TODO: error handling
}
-QVariant LuaRuntime::get_lua_value(int idx) {
+QVariant LuaRuntime::get_lua_value(int idx, QVariant default_value) {
+ if (lua_isnoneornil(state, idx))
+ return default_value;
+
if (lua_isstring(state, idx))
return lua_tostring(state, idx);
@@ -69,9 +72,6 @@ QVariant LuaRuntime::get_lua_value(int idx) {
if (lua_isboolean(state, idx))
return lua_toboolean(state, idx);
- if (lua_isnil(state, idx))
- return 0; // TODO: nil representation
-
return lua_tostring(state, idx);
}
@@ -144,9 +144,63 @@ void LuaRuntime::init_web_lib() {
lua_setfield(state, -2, "keymap");
// lua_pop(state, 1);
+ luaL_Reg tabslib[] = {
+ {"current", &LuaRuntime::lua_get_current_tab_id},
+ };
+ luaL_newlib(state, tabslib); // NOLINT(readability-math-missing-parentheses)
+ lua_setfield(state, -2, "tabs");
+
+ luaL_Reg historylib[] = {
+ {"back", &LuaRuntime::lua_history_back},
+ {"forward", &LuaRuntime::lua_history_forward},
+ };
+ luaL_newlib(state, // NOLINT(readability-math-missing-parentheses)
+ historylib);
+ lua_setfield(state, -2, "history");
// NOLINTEND(modernize-avoid-c-arrays)
}
+int LuaRuntime::lua_get_current_tab_id(lua_State *state) {
+ auto *runtime = LuaRuntime::instance();
+ auto tab_id = runtime->fetch_current_tab_id();
+ lua_pushinteger(state, tab_id);
+ return 1;
+}
+
+int LuaRuntime::lua_history_back(lua_State *state) {
+ auto *runtime = LuaRuntime::instance();
+
+ qsizetype history_index =
+ lua_isnoneornil(state, 1) ? 1 : lua_tointeger(state, 1);
+
+ qsizetype tab_id;
+ if (lua_isnoneornil(state, 2)) {
+ tab_id = runtime->fetch_current_tab_id();
+ } else {
+ tab_id = lua_tointeger(state, 2);
+ }
+
+ emit runtime->history_back_requested(tab_id, history_index);
+ return 1;
+}
+
+int LuaRuntime::lua_history_forward(lua_State *state) {
+ auto *runtime = LuaRuntime::instance();
+
+ qsizetype history_index =
+ lua_isnoneornil(state, 1) ? 1 : lua_tointeger(state, 1);
+
+ qsizetype tab_id;
+ if (lua_isnoneornil(state, 2)) {
+ tab_id = runtime->fetch_current_tab_id();
+ } else {
+ tab_id = lua_tointeger(state, 2);
+ }
+
+ emit runtime->history_forward_requested(tab_id, history_index);
+ return 1;
+}
+
LuaRuntime::~LuaRuntime() {
stop_event_loop();
lua_close(state);
diff --git a/src/LuaRuntime.hpp b/src/LuaRuntime.hpp
index 94d24d8..c90049e 100644
--- a/src/LuaRuntime.hpp
+++ b/src/LuaRuntime.hpp
@@ -5,6 +5,7 @@
#include <lua.hpp>
#include "AsyncEventLoop.hpp"
+#include "utils.hpp"
#include "widgets/WebViewStack.hpp"
#define preserve_top(STATE, BODY) \
@@ -32,15 +33,19 @@ public:
void start_event_loop();
DELEGATE(event_loop, queue_task, queue_task)
- QVariant get_lua_value(int idx);
+ QVariant get_lua_value(int idx, QVariant default_value = 0);
DEFINE_GETTER(get_state, state)
+ DEFINE_FETCHER(qsizetype(), current_tab_id)
+
signals:
void url_opened(QString url, OpenType open_type);
void evaluation_completed(QVariant value);
void evaluation_failed(QString value);
void keymap_add_requested(QString mode, QString keyseq,
std::function<void()>);
+ void history_back_requested(WebViewId webview_id, qsizetype history_index);
+ void history_forward_requested(WebViewId webview_id, qsizetype history_index);
// void output_produced(QVariant value);
protected:
@@ -50,6 +55,9 @@ protected:
static int lua_on_url_open(lua_State *state);
static int lua_on_url_tab_open(lua_State *state);
static int lua_add_keymap(lua_State *state);
+ static int lua_get_current_tab_id(lua_State *state);
+ static int lua_history_back(lua_State *state);
+ static int lua_history_forward(lua_State *state);
private:
lua_State *state;
diff --git a/src/utils.hpp b/src/utils.hpp
index d5d4fc5..eace39e 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -10,3 +10,9 @@
#define DEFINE_GETTER(METHOD, EXPR) \
decltype(auto) METHOD() { return EXPR; }
+
+#define DEFINE_FETCHER(TYPE, NAME) \
+ void set_##NAME##_fetcher(const std::function<TYPE> &fetcher) { \
+ fetch_##NAME = fetcher; \
+ } \
+ std::function<qsizetype()> fetch_##NAME = []() { return -1; };
diff --git a/src/widgets/WebViewStack.cpp b/src/widgets/WebViewStack.cpp
index 19e472e..2d3722a 100644
--- a/src/widgets/WebViewStack.cpp
+++ b/src/widgets/WebViewStack.cpp
@@ -1,6 +1,8 @@
#include <QStackedLayout>
+#include <QWebEngineHistory>
#include <QWebEngineNewWindowRequest>
#include <QWebEngineProfile>
+#include <cstdlib>
#include <vector>
#include "widgets/WebViewStack.hpp"
@@ -12,7 +14,7 @@ WebViewStack::WebViewStack(const Configuration *configuration,
layout->setContentsMargins(0, 0, 0, 0);
layout->setStackingMode(QStackedLayout::StackOne);
- create_new_web_view(configuration->new_tab_url, true);
+ create_new_webview(configuration->new_tab_url, true);
}
void WebViewStack::open_url(const QUrl &url, OpenType open_type) {
@@ -21,125 +23,152 @@ void WebViewStack::open_url(const QUrl &url, OpenType open_type) {
set_current_url(url);
break;
case OpenType::OpenUrlInTab:
- create_new_web_view(url, true);
+ create_new_webview(url, true);
break;
case OpenType::OpenUrlInBgTab:
- create_new_web_view(url, false);
+ create_new_webview(url, false);
break;
case OpenType::OpenUrlInWindow:
- create_new_web_view(url, true);
+ create_new_webview(url, true);
break;
}
}
-WebView *WebViewStack::create_new_web_view(const QUrl &url, bool focus) {
+WebView *WebViewStack::create_new_webview(const QUrl &url, bool focus) {
auto *webview = new WebView(profile);
webview->setUrl(url);
layout->addWidget(webview);
- web_view_list.append(webview);
+ webview_list.append(webview);
connect(webview->page(), &QWebEnginePage::newWindowRequested, this,
- &WebViewStack::on_new_web_view_request);
+ &WebViewStack::on_new_webview_request);
if (focus)
- focus_web_view(web_view_list.length() - 1);
+ focus_webview(webview_list.length() - 1);
return webview;
}
-QList<Tab> WebViewStack::get_tab_list() {
+QList<Tab> WebViewStack::get_webview_list() {
QList<Tab> urls;
- for (auto &view : web_view_list)
+ for (auto &view : webview_list)
urls.append(Tab{.url = view->url().toString(), .title = view->title()});
return urls;
}
-void WebViewStack::on_new_web_view_request(
+void WebViewStack::on_new_webview_request(
const QWebEngineNewWindowRequest &request) {
switch (request.destination()) {
case QWebEngineNewWindowRequest::InNewTab:
- create_new_web_view(request.requestedUrl(), true);
+ create_new_webview(request.requestedUrl(), true);
break;
case QWebEngineNewWindowRequest::InNewBackgroundTab:
- create_new_web_view(request.requestedUrl(), false);
+ create_new_webview(request.requestedUrl(), false);
break;
case QWebEngineNewWindowRequest::InNewWindow:
case QWebEngineNewWindowRequest::InNewDialog:
// TODO: Impl
- create_new_web_view(request.requestedUrl(), true);
+ create_new_webview(request.requestedUrl(), true);
break;
}
}
void WebViewStack::next() {
- if (web_view_list.isEmpty())
+ if (webview_list.isEmpty())
return;
- auto index = current_web_view_index() + 1;
- auto total = web_view_list.length();
+ auto index = current_webview_index() + 1;
+ auto total = webview_list.length();
index = index >= total ? index % total : index;
- focus_web_view(index);
+ focus_webview(index);
}
void WebViewStack::previous() {
- if (web_view_list.isEmpty())
+ if (webview_list.isEmpty())
return;
- auto index = current_web_view_index() - 1;
- auto total = web_view_list.length();
+ auto index = current_webview_index() - 1;
+ auto total = webview_list.length();
index = index < 0 ? total + index : index;
- focus_web_view(index);
+ focus_webview(index);
}
-void WebViewStack::close_current() { close(current_web_view_index()); }
+void WebViewStack::close_current() { close(current_webview_index()); }
-void WebViewStack::close(qsizetype index) {
- if (index < 0 || index >= web_view_list.length())
+void WebViewStack::close(WebViewId index) {
+ if (index < 0 || index >= webview_list.length())
return;
- auto *webview = web_view_list.at(index);
+ auto *webview = webview_list.at(index);
layout->removeWidget(webview);
- web_view_list.removeAt(index);
+ webview_list.removeAt(index);
disconnect(webview->page());
webview->deleteLater();
- focus_web_view(current_web_view_index());
+ focus_webview(current_webview_index());
- if (web_view_list.isEmpty()) {
- create_new_web_view(configuration->new_tab_url, true);
+ if (webview_list.isEmpty()) {
+ create_new_webview(configuration->new_tab_url, true);
}
}
+void WebViewStack::webview_history_back(WebViewId webview_id,
+ qsizetype history_index) {
+ if (webview_id < 0 || webview_id >= webview_list.length())
+ return;
+
+ // TODO: Change this
+ auto *webview = webview_list.at(webview_id);
+ auto *history = webview->history();
+ for (auto i = abs(history_index); i > 0; i--)
+ if (history->canGoBack())
+ history->back();
+}
+
+void WebViewStack::webview_history_forward(WebViewId webview_id,
+ qsizetype history_index) {
+ if (webview_id < 0 || webview_id >= webview_list.length())
+ return;
+
+ // TODO: Change this
+ auto *webview = webview_list.at(webview_id);
+ auto *history = webview->history();
+ for (auto i = abs(history_index); i > 0; i--)
+ if (history->canGoForward())
+ history->forward();
+}
+
std::vector<QUrl> WebViewStack::urls() {
std::vector<QUrl> urls;
- for (auto &view : web_view_list)
+ for (auto &view : webview_list)
urls.push_back(view->url());
return urls;
}
-uint32_t WebViewStack::current_web_view_index() {
+uint32_t WebViewStack::current_webview_index() {
+ qDebug() << "CIRR" << layout->currentIndex();
return layout->currentIndex();
}
-uint32_t WebViewStack::count() { return web_view_list.length(); }
+uint32_t WebViewStack::count() { return webview_list.length(); }
-void WebViewStack::focus_web_view(qsizetype index) {
- if (web_view_list.isEmpty())
+void WebViewStack::focus_webview(WebViewId index) {
+ if (webview_list.isEmpty())
return;
index = std::max((long long)0,
- std::min((long long)index, web_view_list.length() - 1));
+ std::min((long long)index, webview_list.length() - 1));
layout->setCurrentIndex((int)index);
}
QUrl WebViewStack::current_url() {
- if (current_web_view_index() >= web_view_list.length())
+ if (current_webview_index() >= webview_list.length())
return QUrl{};
- return web_view_list.at(current_web_view_index())->url();
+ return webview_list.at(current_webview_index())->url();
}
void WebViewStack::set_current_url(const QUrl &url) {
- if (current_web_view_index() >= web_view_list.length())
+ if (current_webview_index() >= webview_list.length())
return;
- web_view_list.at(current_web_view_index())->setUrl(url);
+ webview_list.at(current_webview_index())->setUrl(url);
}
diff --git a/src/widgets/WebViewStack.hpp b/src/widgets/WebViewStack.hpp
index aa463cc..c975d16 100644
--- a/src/widgets/WebViewStack.hpp
+++ b/src/widgets/WebViewStack.hpp
@@ -8,6 +8,8 @@
#include "Configuration.hpp"
#include "widgets/WebView.hpp"
+using WebViewId = qsizetype;
+
enum OpenType : uint8_t {
OpenUrl,
OpenUrlInTab,
@@ -31,28 +33,31 @@ public:
void open_url(const QUrl &url, OpenType open_type = OpenType::OpenUrl);
std::vector<QUrl> urls();
- QList<Tab> get_tab_list();
- uint32_t current_web_view_index();
+ QList<Tab> get_webview_list();
+ uint32_t current_webview_index();
uint32_t count();
QUrl current_url();
- void focus_web_view(qsizetype index);
+ void focus_webview(WebViewId index);
void next();
void previous();
- void close(qsizetype index);
+ void close(WebViewId index);
void close_current();
+ void webview_history_back(WebViewId webview_id, qsizetype history_index);
+ void webview_history_forward(WebViewId webview_id, qsizetype history_index);
+
private slots:
- void on_new_web_view_request(const QWebEngineNewWindowRequest &request);
+ void on_new_webview_request(const QWebEngineNewWindowRequest &request);
protected:
void set_current_url(const QUrl &url);
- WebView *create_new_web_view(const QUrl &url, bool focus = false);
+ WebView *create_new_webview(const QUrl &url, bool focus = false);
private:
const Configuration *configuration;
QWebEngineProfile *profile;
QStackedLayout *layout;
- QList<WebView *> web_view_list;
+ QList<WebView *> webview_list;
};