aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2025-05-02 12:04:43 +0530
committerAkshay Nair <phenax5@gmail.com>2025-05-02 16:24:38 +0530
commit398b1a4b398324311b6e0f15d2e4ede5ad8500ff (patch)
tree4af9a1b5106dc30d22adc0a4391b5ac006dd7141
parent8a71de53c002b7afdd516cff7190896d40496483 (diff)
downloadnull-browser-398b1a4b398324311b6e0f15d2e4ede5ad8500ff.tar.gz
null-browser-398b1a4b398324311b6e0f15d2e4ede5ad8500ff.zip
Prefix uv with web.uv + add permissions_persistance config option
-rw-r--r--README.md2
-rw-r--r--TODO.org10
-rw-r--r--flake.lock6
-rw-r--r--init.lua3
-rw-r--r--lua/null-browser/extras/dmenu.lua19
-rw-r--r--lua/null-browser/extras/history.lua14
-rw-r--r--lua/null-browser/utils.lua6
-rw-r--r--src/Configuration.hpp22
-rw-r--r--src/LuaRuntime.cpp7
-rw-r--r--src/LuaRuntime.hpp3
-rw-r--r--src/WindowActionRouter.cpp5
-rw-r--r--src/WindowMediator.cpp6
-rw-r--r--src/WindowMediator.hpp1
-rw-r--r--src/main.cpp2
-rw-r--r--src/widgets/BrowserApp.cpp3
-rw-r--r--src/widgets/BrowserWindow.cpp4
16 files changed, 71 insertions, 42 deletions
diff --git a/README.md b/README.md
index 6b080fa..9dc0952 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,8 @@ This web browser is just a stack of web views that can be controlled using lua.
- filter host-names
- **No settings page**
- write some lua
+- **No incognito/private window**
+ - create a window with a custom user data directory and delete it when window is closed
- **No chromium/web extensions**
- inject javascript into pages from your lua config
- **No built-in cryptocurrency**
diff --git a/TODO.org b/TODO.org
index 1019246..6de3412 100644
--- a/TODO.org
+++ b/TODO.org
@@ -1,20 +1,19 @@
** Usable
- [-] Tests for api
-- [ ] Config permission persist (persist_permission_state = 'always' | 'never' | 'in_memory')
- [ ] Permission list/allow/deny api
- [ ] Fullscreen
- [ ] Zoom in/out
- [ ] Run JS in page (web.view.eval_js())
- [ ] Use table for all internals api options?
- [ ] Create window with new profile
+- [ ] User data/profiles management
** Bugs
-- [ ] INVESTIGATE: segfault on api module error
-- [ ] INVESTIGATE: Check why urlchanged doesnt fire for first url open
-- [ ] INVESTIGATE: Segfault on close
-- [ ] INVESTIGATE: Errors in keymap/thread segfaults
+- [ ] INVESTIGATE: Check why urlchanged doesnt fire for first url open sometimes
+- [ ] INVESTIGATE: Segfault on close sometimes
** Next
+- [ ] Configuration validation
- [ ] web.win.* apis (list, current_id)
- [ ] Allow toggling devtools
- [ ] Tests for window
@@ -26,7 +25,6 @@
- [ ] Allow pattern filtering for event listeners
- [ ] Allow tab_id, win_id filtering for event listeners
- [ ] Handle resource cleanup + signal disconnecting
-- [ ] Profiles
- [ ] Private window (in-memory profile)
- [ ] Read page contents via lua
diff --git a/flake.lock b/flake.lock
index 1387dc3..70d65af 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1744868846,
- "narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=",
+ "lastModified": 1745377448,
+ "narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c",
+ "rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
"type": "github"
},
"original": {
diff --git a/init.lua b/init.lua
index 031af8f..ddf87d8 100644
--- a/init.lua
+++ b/init.lua
@@ -20,6 +20,7 @@ require 'null-browser.defaults.vi'.setup {
transform_url_input = search_engines.transform_url_input,
}
+-- web.set('permissions_persistance', 'never')
web.event.add_listener('PermissionRequested', {
callback = function(event)
dmenu.select({ 'Allow', 'Deny' }, { prompt = 'Requesting permission for ' .. event.permission_type },
@@ -38,7 +39,7 @@ web.event.add_listener('NotificationReceived', {
callback = function(event)
-- TODO: Add action/click (-A)
local args = { '-a', 'null-browser', '-r', event.tag, event.title, event.message }
- uv.spawn('notify-send', { args = args }, function(code)
+ web.uv.spawn('notify-send', { args = args }, function(code)
if code ~= 0 then
print('[notify-send] Exit with status code: ' .. code)
end
diff --git a/lua/null-browser/extras/dmenu.lua b/lua/null-browser/extras/dmenu.lua
index c7a941f..fc92b35 100644
--- a/lua/null-browser/extras/dmenu.lua
+++ b/lua/null-browser/extras/dmenu.lua
@@ -1,12 +1,9 @@
---- @type table
-uv = uv
-
local dmenu = {}
function dmenu.select(list, opts, callback)
local selection = nil
- local stdin = uv.new_pipe();
- local stdout = uv.new_pipe();
+ local stdin = web.uv.new_pipe();
+ local stdout = web.uv.new_pipe();
local args = opts.args or {}
if opts.prompt then
table.insert(args, '-p')
@@ -17,9 +14,9 @@ function dmenu.select(list, opts, callback)
table.insert(args, opts.input)
end
- uv.spawn('dmenu', { args = args, stdio = { stdin, stdout, nil } }, function(code)
- uv.close(stdout)
- uv.close(stdin)
+ web.uv.spawn('dmenu', { args = args, stdio = { stdin, stdout, nil } }, function(code)
+ web.uv.close(stdout)
+ web.uv.close(stdin)
if code == 0 then
callback(nil, selection)
else
@@ -27,14 +24,14 @@ function dmenu.select(list, opts, callback)
end
end)
- uv.read_start(stdout, function(_, data)
+ web.uv.read_start(stdout, function(_, data)
if data then selection = data end
end)
for _, value in ipairs(list) do
- uv.write(stdin, value .. '\n')
+ web.uv.write(stdin, value .. '\n')
end
- uv.shutdown(stdin)
+ web.uv.shutdown(stdin)
end
function dmenu.input(opts, callback)
diff --git a/lua/null-browser/extras/history.lua b/lua/null-browser/extras/history.lua
index 8106178..d1f58d0 100644
--- a/lua/null-browser/extras/history.lua
+++ b/lua/null-browser/extras/history.lua
@@ -6,11 +6,11 @@ local history = {
local hook_registered = false
function history.list()
- local file = uv.fs_open(history.path, 'r', 438)
+ local file = web.uv.fs_open(history.path, 'r', 438)
if not file then return {} end
- local stat = assert(uv.fs_fstat(file))
- local data = assert(uv.fs_read(file, stat.size))
- assert(uv.fs_close(file))
+ local stat = assert(web.uv.fs_fstat(file))
+ local data = assert(web.uv.fs_read(file, stat.size))
+ assert(web.uv.fs_close(file))
local urls = {}
for line in string.gmatch(data, '[^\r\n]+') do
@@ -33,11 +33,11 @@ end
function history.update(func)
local urls = history.list()
- local file = assert(uv.fs_open(history.path, 'w', 438))
+ local file = assert(web.uv.fs_open(history.path, 'w', 438))
urls = func(urls)
local contents = table.concat(urls, '\n')
- assert(uv.fs_write(file, contents))
- assert(uv.fs_close(file))
+ assert(web.uv.fs_write(file, contents))
+ assert(web.uv.fs_close(file))
end
function history.add(url)
diff --git a/lua/null-browser/utils.lua b/lua/null-browser/utils.lua
index b6ff40a..2fe44e1 100644
--- a/lua/null-browser/utils.lua
+++ b/lua/null-browser/utils.lua
@@ -2,6 +2,12 @@
_G.web = _G.web or {}
web.utils = web.utils or {}
+--- luv api
+--- @type table
+--- @link https://github.com/luvit/luv/blob/master/docs.md
+--- @diagnostic disable-next-line: undefined-global
+web.uv = web.uv or nil
+
local inspector = require 'null-browser.inspect'
--- Returns human-readable string representation of Lua tables
diff --git a/src/Configuration.hpp b/src/Configuration.hpp
index 1f861fa..7c97b72 100644
--- a/src/Configuration.hpp
+++ b/src/Configuration.hpp
@@ -15,6 +15,7 @@ private:
{"user_agent", QWebEngineProfile::defaultProfile()->httpUserAgent()},
{"downloads_dir", QWebEngineProfile::defaultProfile()->downloadPath()},
{"app_data_dir", QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)},
+ {"permissions_persistance", "always"},
};
QDir config_dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
@@ -42,6 +43,22 @@ public:
QString new_view_url() const { return get_config("new_view_url").toString(); }
QString user_agent() const { return get_config("user_agent").toString(); }
QString downloads_dir() const { return get_config("downloads_dir").toString(); }
+ QString permissions_persistance() const {
+ return get_config("permissions_persistance").toString();
+ }
+
+ QWebEngineProfile::PersistentPermissionsPolicy permission_persistance_policy() const {
+ return to_permission_persistance_policy(permissions_persistance());
+ }
+
+ static QWebEngineProfile::PersistentPermissionsPolicy
+ to_permission_persistance_policy(const QString &persistance) {
+ if (persistance == "session")
+ return QWebEngineProfile::PersistentPermissionsPolicy::StoreInMemory;
+ if (persistance == "never")
+ return QWebEngineProfile::PersistentPermissionsPolicy::AskEveryTime;
+ return QWebEngineProfile::PersistentPermissionsPolicy::StoreOnDisk;
+ }
DEFINE_GETTER(get_config_dir, config_dir)
DEFINE_SETTER(set_config_dir, config_dir)
@@ -53,11 +70,14 @@ private:
void on_update(const QString &name, const QVariant &value) {
if (name == "user_agent")
emit user_agent_updated(value.toString());
- if (name == "downloads_dir")
+ else if (name == "downloads_dir")
emit downloads_dir_updated(value.toString());
+ else if (name == "permissions_persistance")
+ emit permissions_persistance_updated(value.toString());
}
signals:
void user_agent_updated(const QString &value);
void downloads_dir_updated(const QString &value);
+ void permissions_persistance_updated(const QString &value);
};
diff --git a/src/LuaRuntime.cpp b/src/LuaRuntime.cpp
index 07ddb67..e9dc86f 100644
--- a/src/LuaRuntime.cpp
+++ b/src/LuaRuntime.cpp
@@ -35,7 +35,8 @@ void LuaRuntime::start_event_loop() {
luv_set_loop(state, event_loop->get_uv_loop());
luv_set_callback(state, &luv_callback);
luaopen_luv(state);
- lua_setglobal(state, uv_global_name);
+ lua_setglobal(state, "uv");
+ luaL_dostring(state, "web.uv = uv");
}
void LuaRuntime::stop_event_loop() {
@@ -46,13 +47,13 @@ void LuaRuntime::stop_event_loop() {
// Clear the uv global
lua_pushnil(state);
- lua_setglobal(state, uv_global_name);
+ lua_setglobal(state, "uv");
lua_gc(state, LUA_GCCOLLECT, 0);
}
void LuaRuntime::init_web_api() {
luaL_newlib(state, internals_api);
- lua_setglobal(state, internals_global_name);
+ lua_setglobal(state, "__internals");
require_module("null-browser.api");
}
diff --git a/src/LuaRuntime.hpp b/src/LuaRuntime.hpp
index 2af61f7..527501e 100644
--- a/src/LuaRuntime.hpp
+++ b/src/LuaRuntime.hpp
@@ -23,9 +23,6 @@
class LuaRuntime : public QObject {
Q_OBJECT
- const char *uv_global_name = "uv";
- const char *internals_global_name = "__internals";
-
public:
static LuaRuntime &instance() {
static LuaRuntime runtime;
diff --git a/src/WindowActionRouter.cpp b/src/WindowActionRouter.cpp
index 721a3e7..7270855 100644
--- a/src/WindowActionRouter.cpp
+++ b/src/WindowActionRouter.cpp
@@ -34,6 +34,11 @@ void WindowActionRouter::initialize(Configuration *config) {
for (auto &win_match : window_map)
win_match.second->mediator()->update_downloads_dir(downloads_dir);
});
+ connect(configuration, &Configuration::permissions_persistance_updated, this,
+ [this](const QString &persistance) {
+ for (auto &win_match : window_map)
+ win_match.second->mediator()->update_permissions_persistance(persistance);
+ });
// History
connect(&runtime, &LuaRuntime::history_back_requested, this,
diff --git a/src/WindowMediator.cpp b/src/WindowMediator.cpp
index cb677ee..fa9a25e 100644
--- a/src/WindowMediator.cpp
+++ b/src/WindowMediator.cpp
@@ -23,6 +23,12 @@ void WindowMediator::update_downloads_dir(const QString &downloads_dir) {
profile->setDownloadPath(downloads_dir);
}
+void WindowMediator::update_permissions_persistance(const QString &persistance) {
+ auto *profile = webview_stack->get_profile();
+ auto persistance_policy = Configuration::to_permission_persistance_policy(persistance);
+ profile->setPersistentPermissionsPolicy(persistance_policy);
+}
+
WindowMediator::~WindowMediator() {
disconnect(this);
delete webview_stack;
diff --git a/src/WindowMediator.hpp b/src/WindowMediator.hpp
index 0a27f2e..163ab7a 100644
--- a/src/WindowMediator.hpp
+++ b/src/WindowMediator.hpp
@@ -34,6 +34,7 @@ signals:
public slots:
void update_user_agent(const QString &user_agent);
void update_downloads_dir(const QString &downloads_dir);
+ void update_permissions_persistance(const QString &persistance);
private:
WebViewStack *webview_stack;
diff --git a/src/main.cpp b/src/main.cpp
index dc67c8a..ee94ad3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -12,7 +12,7 @@ QCommandLineParser *create_cli_parser() {
parser->addPositionalArgument("url", "URL(s) to open", "[url]");
parser->addOptions({
{{"e", "expr"}, "Lua expression to execute", "lua"},
- {{"c", "config-dir"}, "Config directory for null browser", "dir"},
+ {{"C", "config-dir"}, "Config directory for null browser", "dir"},
});
return parser;
diff --git a/src/widgets/BrowserApp.cpp b/src/widgets/BrowserApp.cpp
index 32ac598..54fd44a 100644
--- a/src/widgets/BrowserApp.cpp
+++ b/src/widgets/BrowserApp.cpp
@@ -41,8 +41,7 @@ BrowserApp::BrowserApp(Configuration &configuration) : configuration(configurati
auto *event = new NotificationReceivedEvent(std::move(notification));
WindowActionRouter::instance().dispatch_event(event);
});
- profile->setPersistentPermissionsPolicy(
- QWebEngineProfile::PersistentPermissionsPolicy::StoreInMemory);
+ profile->setPersistentPermissionsPolicy(configuration.permission_persistance_policy());
}
connect(&window_action_router, &WindowActionRouter::new_window_requested, this,
diff --git a/src/widgets/BrowserWindow.cpp b/src/widgets/BrowserWindow.cpp
index d1b9c44..8e1555f 100644
--- a/src/widgets/BrowserWindow.cpp
+++ b/src/widgets/BrowserWindow.cpp
@@ -22,10 +22,6 @@ BrowserWindow::BrowserWindow(const Configuration &configuration, QWebEngineProfi
layout->setSpacing(0);
centralWidget()->setLayout(layout);
- // Webengine profile
- profile->setDownloadPath(configuration.downloads_dir());
- profile->setHttpUserAgent(configuration.user_agent());
-
// Stack of web views
auto *webview_stack = new WebViewStack(&configuration, profile);
layout->addWidget(webview_stack);