LibWebView+UI: Disable primary paste on unsupported systems

A selection clipboard is not available on all systems. The UI now
controls whether this feature is available.
This commit is contained in:
Timothy Flynn 2026-05-21 08:30:18 -04:00 committed by Tim Flynn
parent adf5e0a226
commit 082281da62
10 changed files with 57 additions and 3 deletions

View file

@ -397,7 +397,7 @@
<input id="enable-autoscroll" type="checkbox" switch />
</div>
</div>
<div class="card-group card-separator">
<div class="card-group card-separator" id="enable-primary-paste-group">
<div class="inline-container">
<label for="enable-primary-paste">
Enable primary pasting
@ -738,6 +738,7 @@
});
document.addEventListener("WebUILoaded", () => {
ladybird.sendMessage("loadFeatures");
ladybird.sendMessage("loadCurrentSettings");
});
</script>

View file

@ -1,8 +1,13 @@
const enableAutoscroll = document.querySelector("#enable-autoscroll");
const enablePrimaryPaste = document.querySelector("#enable-primary-paste");
const enablePrimaryPasteGroup = document.querySelector("#enable-primary-paste-group");
let BROWSING_BEHAVIOR = {};
const loadFeatures = features => {
enablePrimaryPasteGroup.classList.toggle("hidden", !features?.primaryPaste);
};
const loadSettings = settings => {
BROWSING_BEHAVIOR = settings.browsingBehavior || {};
@ -21,7 +26,9 @@ addChangeHandler(enableAutoscroll, "enableAutoscroll");
addChangeHandler(enablePrimaryPaste, "enablePrimaryPaste");
document.addEventListener("WebUIMessage", event => {
if (event.detail.name === "loadSettings") {
if (event.detail.name === "loadFeatures") {
loadFeatures(event.detail.data);
} else if (event.detail.name === "loadSettings") {
loadSettings(event.detail.data);
}
});

View file

@ -1089,6 +1089,11 @@ void Application::display_error_dialog(StringView error_message) const
warnln("{}", error_message);
}
bool Application::supports_clipboard_type(ClipboardType type) const
{
return type == ClipboardType::Text;
}
Utf16String Application::clipboard_text(ClipboardType) const
{
if (!m_clipboard.has_value())

View file

@ -128,7 +128,9 @@ public:
Text,
Selection,
};
virtual bool supports_clipboard_type(ClipboardType) const;
virtual Utf16String clipboard_text(ClipboardType = ClipboardType::Text) const;
virtual Vector<Web::Clipboard::SystemClipboardRepresentation> clipboard_entries() const;
virtual void insert_clipboard_entry(Web::Clipboard::SystemClipboardRepresentation);

View file

@ -464,6 +464,17 @@ BrowsingBehavior Settings::parse_browsing_behavior(JsonValue const& settings)
return browsing_behavior;
}
BrowsingBehavior Settings::browsing_behavior() const
{
auto browsing_behavior = m_browsing_behavior;
// Override browsing behaviors depending on what the system supports. We do this here, rather than persisting the
// setting override, so that we don't persist unsupported behavior when headless mode is used.
browsing_behavior.enable_primary_paste &= Application::the().supports_clipboard_type(Application::ClipboardType::Selection);
return browsing_behavior;
}
void Settings::set_browsing_behavior(BrowsingBehavior browsing_behavior)
{
m_browsing_behavior = browsing_behavior;

View file

@ -104,7 +104,7 @@ public:
void set_languages(Vector<String>);
static BrowsingBehavior parse_browsing_behavior(JsonValue const&);
BrowsingBehavior const& browsing_behavior() const { return m_browsing_behavior; }
BrowsingBehavior browsing_behavior() const;
void set_browsing_behavior(BrowsingBehavior);
Optional<SearchEngine> const& search_engine() const { return m_search_engine; }

View file

@ -34,6 +34,9 @@ static StringView config_variable_type_to_string(JsonValue::Type type)
void SettingsUI::register_interfaces()
{
register_interface("loadFeatures"sv, [this](auto const&) {
load_features();
});
register_interface("loadCurrentSettings"sv, [this](auto const&) {
load_current_settings();
});
@ -104,6 +107,14 @@ void SettingsUI::register_interfaces()
});
}
void SettingsUI::load_features()
{
JsonObject features;
features.set("primaryPaste"_string, Application::the().supports_clipboard_type(Application::ClipboardType::Selection));
async_send_message("loadFeatures"sv, move(features));
}
void SettingsUI::load_current_settings()
{
auto settings = WebView::Application::settings().serialize_json();

View file

@ -17,6 +17,7 @@ class WEBVIEW_API SettingsUI : public WebUI {
private:
virtual void register_interfaces() override;
void load_features();
void load_current_settings();
void set_new_tab_page_url(JsonValue const&);

View file

@ -210,6 +210,20 @@ static QClipboard::Mode clipboard_mode(QClipboard const& clipboard, Application:
VERIFY_NOT_REACHED();
}
bool Application::supports_clipboard_type(ClipboardType type) const
{
if (browser_options().headless_mode.has_value())
return WebView::Application::supports_clipboard_type(type);
switch (type) {
case WebView::Application::ClipboardType::Text:
return true;
case WebView::Application::ClipboardType::Selection:
return QGuiApplication::clipboard()->supportsSelection();
}
VERIFY_NOT_REACHED();
}
Utf16String Application::clipboard_text(ClipboardType type) const
{
if (browser_options().headless_mode.has_value())

View file

@ -52,7 +52,9 @@ private:
virtual void display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const override;
virtual void display_error_dialog(StringView error_message) const override;
virtual bool supports_clipboard_type(ClipboardType) const override;
virtual Utf16String clipboard_text(ClipboardType) const override;
virtual Vector<Web::Clipboard::SystemClipboardRepresentation> clipboard_entries() const override;
virtual void insert_clipboard_entry(Web::Clipboard::SystemClipboardRepresentation) override;