LibWeb+LibWebView+WebContent: Add a setting to control autoscrolling

This commit is contained in:
Timothy Flynn
2026-04-13 10:55:24 -04:00
committed by Tim Flynn
parent 6cf4fa80a7
commit 79893b9cef
Notes: github-actions[bot] 2026-04-13 17:51:31 +00:00
14 changed files with 148 additions and 1 deletions

View File

@@ -365,6 +365,21 @@
</div>
</div>
</div>
<h3 class="card-title">Browsing Behavior</h3>
<div class="card">
<div class="card-body">
<div class="card-group">
<div class="inline-container">
<label for="enable-autoscroll">Enable autoscrolling</label>
<input id="enable-autoscroll" type="checkbox" switch />
</div>
<p class="description">
Scroll pages by pressing the middle mouse button and moving the mouse.
</p>
</div>
</div>
</div>
</div>
<div class="tab-panel" id="tab-search">
@@ -620,6 +635,7 @@
};
</script>
<script src="resource://ladybird/about-pages/settings/browsing-behavior.js" type="module"></script>
<script src="resource://ladybird/about-pages/settings/default-zoom-level.js" type="module"></script>
<script src="resource://ladybird/about-pages/settings/languages.js" type="module"></script>
<script src="resource://ladybird/about-pages/settings/network.js" type="module"></script>

View File

@@ -0,0 +1,20 @@
const enableAutoscroll = document.querySelector("#enable-autoscroll");
let BROWSING_BEHAVIOR = {};
const loadSettings = settings => {
BROWSING_BEHAVIOR = settings.browsingBehavior || {};
enableAutoscroll.checked = !!BROWSING_BEHAVIOR.enableAutoscroll;
};
enableAutoscroll.addEventListener("change", () => {
BROWSING_BEHAVIOR.enableAutoscroll = enableAutoscroll.checked;
ladybird.sendMessage("setBrowsingBehavior", BROWSING_BEHAVIOR);
});
document.addEventListener("WebUIMessage", event => {
if (event.detail.name === "loadSettings") {
loadSettings(event.detail.data);
}
});

View File

@@ -1186,6 +1186,9 @@ bool EventHandler::initiate_paragraph_selection(DOM::Document& document, Paintin
void EventHandler::run_mousedown_default_actions(DOM::Document& document, CSSPixelPoint visual_viewport_position, CSSPixelPoint viewport_position, unsigned button, unsigned modifiers, int click_count)
{
if (button == UIEvents::MouseButton::Middle) {
if (!m_navigable->page().enable_autoscroll())
return;
auto hit = paint_root()->hit_test(visual_viewport_position, Painting::HitTestType::Exact);
if (!hit.has_value())
return;

View File

@@ -130,6 +130,9 @@ public:
bool should_block_pop_ups() const { return m_should_block_pop_ups; }
void set_should_block_pop_ups(bool b) { m_should_block_pop_ups = b; }
bool enable_autoscroll() const { return m_enable_autoscroll; }
void set_enable_autoscroll(bool b) { m_enable_autoscroll = b; }
bool is_webdriver_active() const { return m_is_webdriver_active; }
void set_is_webdriver_active(bool b) { m_is_webdriver_active = b; }
@@ -286,8 +289,8 @@ private:
GC::Ptr<HTML::TraversableNavigable> m_top_level_traversable;
bool m_is_scripting_enabled { true };
bool m_should_block_pop_ups { true };
bool m_enable_autoscroll { true };
// https://w3c.github.io/webdriver/#dfn-webdriver-active-flag
// The webdriver-active flag is set to true when the user agent is under remote control. It is initially false.

View File

@@ -10,6 +10,8 @@
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <LibCore/StandardPaths.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
#include <LibURL/Parser.h>
#include <LibUnicode/Locale.h>
#include <LibWebView/Application.h>
@@ -29,6 +31,9 @@ static constexpr double INITIAL_ZOOM_LEVEL_FACTOR = 1.0;
static constexpr auto LANGUAGES_KEY = "languages"sv;
static auto DEFAULT_LANGUAGE = "en"_string;
static constexpr auto BROWSING_BEHAVIOR_KEY = "browsingBehavior"sv;
static constexpr auto ENABLE_AUTOSCROLL_KEY = "enableAutoscroll"sv;
static constexpr auto SEARCH_ENGINE_KEY = "searchEngine"sv;
static constexpr auto SEARCH_ENGINE_CUSTOM_KEY = "custom"sv;
static constexpr auto SEARCH_ENGINE_NAME_KEY = "name"sv;
@@ -78,6 +83,9 @@ Settings Settings::create(Badge<Application>)
if (auto languages = settings_json.value().get(LANGUAGES_KEY); languages.has_value())
settings.m_languages = parse_json_languages(*languages);
if (auto browsing_behavior = settings_json.value().get(BROWSING_BEHAVIOR_KEY); browsing_behavior.has_value())
settings.m_browsing_behavior = parse_browsing_behavior(*browsing_behavior);
if (auto search_engine = settings_json.value().get_object(SEARCH_ENGINE_KEY); search_engine.has_value()) {
if (auto custom_engines = search_engine->get_array(SEARCH_ENGINE_CUSTOM_KEY); custom_engines.has_value()) {
custom_engines->for_each([&](JsonValue const& engine) {
@@ -156,6 +164,10 @@ JsonValue Settings::serialize_json() const
settings.set(LANGUAGES_KEY, move(languages));
JsonObject browsing_behavior;
browsing_behavior.set(ENABLE_AUTOSCROLL_KEY, m_browsing_behavior.enable_autoscroll);
settings.set(BROWSING_BEHAVIOR_KEY, move(browsing_behavior));
JsonArray custom_search_engines;
custom_search_engines.ensure_capacity(m_custom_search_engines.size());
@@ -290,6 +302,28 @@ void Settings::set_languages(Vector<String> languages)
observer.languages_changed();
}
BrowsingBehavior Settings::parse_browsing_behavior(JsonValue const& settings)
{
if (!settings.is_object())
return {};
BrowsingBehavior browsing_behavior;
if (auto enable_autoscroll = settings.as_object().get_bool(ENABLE_AUTOSCROLL_KEY); enable_autoscroll.has_value())
browsing_behavior.enable_autoscroll = *enable_autoscroll;
return browsing_behavior;
}
void Settings::set_browsing_behavior(BrowsingBehavior browsing_behavior)
{
m_browsing_behavior = browsing_behavior;
persist_settings();
for (auto& observer : m_observers)
observer.browsing_behavior_changed();
}
void Settings::set_search_engine(Optional<StringView> search_engine_name)
{
if (search_engine_name.has_value())
@@ -524,3 +558,23 @@ SiteSetting::SiteSetting()
}
}
namespace IPC {
template<>
ErrorOr<void> encode(Encoder& encoder, WebView::BrowsingBehavior const& browsing_behavior)
{
TRY(encoder.encode(browsing_behavior.enable_autoscroll));
return {};
}
template<>
ErrorOr<WebView::BrowsingBehavior> decode(Decoder& decoder)
{
auto enable_autoscroll = TRY(decoder.decode<bool>());
return WebView::BrowsingBehavior { enable_autoscroll };
}
}

View File

@@ -11,6 +11,7 @@
#include <AK/JsonValue.h>
#include <AK/Optional.h>
#include <LibHTTP/Cache/DiskCacheSettings.h>
#include <LibIPC/Forward.h>
#include <LibURL/URL.h>
#include <LibWebView/Autocomplete.h>
#include <LibWebView/Forward.h>
@@ -19,6 +20,10 @@
namespace WebView {
struct BrowsingBehavior {
bool enable_autoscroll { true };
};
struct SiteSetting {
SiteSetting();
@@ -44,6 +49,7 @@ public:
virtual void show_bookmarks_bar_changed() { }
virtual void default_zoom_level_factor_changed() { }
virtual void languages_changed() { }
virtual void browsing_behavior_changed() { }
virtual void search_engine_changed() { }
virtual void autocomplete_engine_changed() { }
virtual void autoplay_settings_changed() { }
@@ -71,6 +77,10 @@ public:
Vector<String> const& languages() const { return m_languages; }
void set_languages(Vector<String>);
static BrowsingBehavior parse_browsing_behavior(JsonValue const&);
BrowsingBehavior const& browsing_behavior() const { return m_browsing_behavior; }
void set_browsing_behavior(BrowsingBehavior);
Optional<SearchEngine> const& search_engine() const { return m_search_engine; }
void set_search_engine(Optional<StringView> search_engine_name);
@@ -114,6 +124,7 @@ private:
bool m_show_bookmarks_bar { true };
double m_default_zoom_level_factor { 0 };
Vector<String> m_languages;
BrowsingBehavior m_browsing_behavior;
Optional<SearchEngine> m_search_engine;
Vector<SearchEngine> m_custom_search_engines;
Optional<AutocompleteEngine> m_autocomplete_engine;
@@ -127,3 +138,13 @@ private:
};
}
namespace IPC {
template<>
WEBVIEW_API ErrorOr<void> encode(Encoder&, WebView::BrowsingBehavior const&);
template<>
WEBVIEW_API ErrorOr<WebView::BrowsingBehavior> decode(Decoder&);
}

View File

@@ -644,6 +644,7 @@ void ViewImplementation::initialize_client(CreateNewClient create_new_client)
default_zoom_level_factor_changed();
languages_changed();
browsing_behavior_changed();
autoplay_settings_changed();
global_privacy_control_changed();
@@ -722,6 +723,12 @@ void ViewImplementation::languages_changed()
client().async_set_preferred_languages(page_id(), languages);
}
void ViewImplementation::browsing_behavior_changed()
{
auto const& browsing_behavior = Application::settings().browsing_behavior();
client().async_set_browsing_behavior(page_id(), browsing_behavior);
}
void ViewImplementation::autoplay_settings_changed()
{
auto const& autoplay_settings = Application::settings().autoplay_settings();

View File

@@ -307,6 +307,7 @@ protected:
virtual void default_zoom_level_factor_changed() override;
virtual void languages_changed() override;
virtual void browsing_behavior_changed() override;
virtual void autoplay_settings_changed() override;
virtual void global_privacy_control_changed() override;

View File

@@ -27,6 +27,9 @@ void SettingsUI::register_interfaces()
register_interface("setLanguages"sv, [this](auto const& data) {
set_languages(data);
});
register_interface("setBrowsingBehavior"sv, [this](auto const& data) {
set_browsing_behavior(data);
});
register_interface("loadAvailableEngines"sv, [this](auto const&) {
load_available_engines();
@@ -113,6 +116,14 @@ void SettingsUI::set_languages(JsonValue const& languages)
load_current_settings();
}
void SettingsUI::set_browsing_behavior(JsonValue const& browsing_behavior)
{
auto parsed_browsing_behavior = Settings::parse_browsing_behavior(browsing_behavior);
WebView::Application::settings().set_browsing_behavior(parsed_browsing_behavior);
load_current_settings();
}
void SettingsUI::load_available_engines()
{
JsonArray search_engines;

View File

@@ -22,6 +22,7 @@ private:
void set_new_tab_page_url(JsonValue const&);
void set_default_zoom_level_factor(JsonValue const&);
void set_languages(JsonValue const&);
void set_browsing_behavior(JsonValue const&);
void load_available_engines();
void set_search_engine(JsonValue const&);

View File

@@ -1181,6 +1181,12 @@ void ConnectionFromClient::set_preferred_languages(u64, Vector<String> preferred
Web::ResourceLoader::the().set_preferred_languages(move(preferred_languages));
}
void ConnectionFromClient::set_browsing_behavior(u64 page_id, WebView::BrowsingBehavior browsing_behavior)
{
if (auto page = this->page(page_id); page.has_value())
page->page().set_enable_autoscroll(browsing_behavior.enable_autoscroll);
}
void ConnectionFromClient::set_enable_global_privacy_control(u64, bool enable)
{
Web::ResourceLoader::the().set_enable_global_privacy_control(enable);

View File

@@ -114,6 +114,7 @@ private:
virtual void set_preferred_contrast(u64 page_id, Web::CSS::PreferredContrast) override;
virtual void set_preferred_motion(u64 page_id, Web::CSS::PreferredMotion) override;
virtual void set_preferred_languages(u64 page_id, Vector<String>) override;
virtual void set_browsing_behavior(u64 page_id, WebView::BrowsingBehavior) override;
virtual void set_enable_global_privacy_control(u64 page_id, bool) override;
virtual void set_has_focus(u64 page_id, bool) override;
virtual void set_is_scripting_enabled(u64 page_id, bool) override;

View File

@@ -19,6 +19,7 @@
#include <LibWebView/Attribute.h>
#include <LibWebView/DOMNodeProperties.h>
#include <LibWebView/PageInfo.h>
#include <LibWebView/Settings.h>
endpoint WebContentServer
{
@@ -102,6 +103,7 @@ endpoint WebContentServer
set_preferred_contrast(u64 page_id, Web::CSS::PreferredContrast contrast) =|
set_preferred_motion(u64 page_id, Web::CSS::PreferredMotion motion) =|
set_preferred_languages(u64 page_id, Vector<String> preferred_languages) =|
set_browsing_behavior(u64 page_id, WebView::BrowsingBehavior browsing_behavior) =|
set_enable_global_privacy_control(u64 page_id, bool enable) =|
set_has_focus(u64 page_id, bool has_focus) =|
set_is_scripting_enabled(u64 page_id, bool is_scripting_enabled) =|

View File

@@ -79,6 +79,7 @@ set(ABOUT_PAGES
list(TRANSFORM ABOUT_PAGES PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/ladybird/about-pages/")
set(ABOUT_SETTINGS_RESOURCES
browsing-behavior.js
default-zoom-level.js
languages.js
network.js