diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index cd6871d1170..5f3e7ab6825 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -27,6 +27,7 @@ namespace WebView { Application* Application::s_the = nullptr; Application::Application() + : m_settings(Settings::create({})) { VERIFY(!s_the); s_the = this; @@ -57,7 +58,7 @@ Application::~Application() s_the = nullptr; } -void Application::initialize(Main::Arguments const& arguments, URL::URL new_tab_page_url) +void Application::initialize(Main::Arguments const& arguments) { #ifndef AK_OS_WINDOWS // Increase the open file limit, as the default limits on Linux cause us to run out of file descriptors with around 15 tabs open. @@ -152,9 +153,8 @@ void Application::initialize(Main::Arguments const& arguments, URL::URL new_tab_ disable_site_isolation = true; m_browser_options = { - .urls = sanitize_urls(raw_urls, new_tab_page_url), + .urls = sanitize_urls(raw_urls, m_settings.new_tab_page_url()), .raw_urls = move(raw_urls), - .new_tab_page_url = move(new_tab_page_url), .certificates = move(certificates), .new_window = new_window ? NewWindow::Yes : NewWindow::No, .force_new_process = force_new_process ? ForceNewProcess::Yes : ForceNewProcess::No, diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index b51f35c2cf6..db73ecb4bd0 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace WebView { @@ -35,6 +36,8 @@ public: static Application& the() { return *s_the; } + static Settings& settings() { return the().m_settings; } + static BrowserOptions const& browser_options() { return the().m_browser_options; } static WebContentOptions& web_content_options() { return the().m_web_content_options; } @@ -69,10 +72,10 @@ public: protected: template ApplicationType> - static NonnullOwnPtr create(Main::Arguments& arguments, URL::URL new_tab_page_url) + static NonnullOwnPtr create(Main::Arguments& arguments) { auto app = adopt_own(*new ApplicationType { {}, arguments }); - app->initialize(arguments, move(new_tab_page_url)); + app->initialize(arguments); return app; } @@ -87,7 +90,7 @@ protected: virtual Optional ask_user_for_download_folder() const { return {}; } private: - void initialize(Main::Arguments const& arguments, URL::URL new_tab_page_url); + void initialize(Main::Arguments const& arguments); void launch_spare_web_content_process(); ErrorOr launch_request_server(); @@ -127,6 +130,8 @@ private: static Application* s_the; + Settings m_settings; + BrowserOptions m_browser_options; WebContentOptions m_web_content_options; @@ -150,11 +155,11 @@ private: } -#define WEB_VIEW_APPLICATION(ApplicationType) \ -public: \ - static NonnullOwnPtr create(Main::Arguments& arguments, URL::URL new_tab_page_url) \ - { \ - return WebView::Application::create(arguments, move(new_tab_page_url)); \ - } \ - \ +#define WEB_VIEW_APPLICATION(ApplicationType) \ +public: \ + static NonnullOwnPtr create(Main::Arguments& arguments) \ + { \ + return WebView::Application::create(arguments); \ + } \ + \ ApplicationType(Badge, Main::Arguments&); diff --git a/Libraries/LibWebView/BrowserProcess.cpp b/Libraries/LibWebView/BrowserProcess.cpp index f2a8296c2ea..9498694ad51 100644 --- a/Libraries/LibWebView/BrowserProcess.cpp +++ b/Libraries/LibWebView/BrowserProcess.cpp @@ -117,13 +117,13 @@ void UIProcessConnectionFromClient::die() void UIProcessConnectionFromClient::create_new_tab(Vector urls) { if (on_new_tab) - on_new_tab(sanitize_urls(urls, Application::browser_options().new_tab_page_url)); + on_new_tab(sanitize_urls(urls, Application::settings().new_tab_page_url())); } void UIProcessConnectionFromClient::create_new_window(Vector urls) { if (on_new_window) - on_new_window(sanitize_urls(urls, Application::browser_options().new_tab_page_url)); + on_new_window(sanitize_urls(urls, Application::settings().new_tab_page_url())); } } diff --git a/Libraries/LibWebView/CMakeLists.txt b/Libraries/LibWebView/CMakeLists.txt index f628ab8fbf9..60b7fd49658 100644 --- a/Libraries/LibWebView/CMakeLists.txt +++ b/Libraries/LibWebView/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES ProcessHandle.cpp ProcessManager.cpp SearchEngine.cpp + Settings.cpp SiteIsolation.cpp SourceHighlighter.cpp URL.cpp diff --git a/Libraries/LibWebView/Forward.h b/Libraries/LibWebView/Forward.h index 2056ee0d205..860a7a65744 100644 --- a/Libraries/LibWebView/Forward.h +++ b/Libraries/LibWebView/Forward.h @@ -15,6 +15,7 @@ class CookieJar; class Database; class OutOfProcessWebView; class ProcessManager; +class Settings; class ViewImplementation; class WebContentClient; diff --git a/Libraries/LibWebView/Options.h b/Libraries/LibWebView/Options.h index 18f8527d7cc..88e242dff1a 100644 --- a/Libraries/LibWebView/Options.h +++ b/Libraries/LibWebView/Options.h @@ -62,7 +62,6 @@ constexpr inline u16 default_devtools_port = 6000; struct BrowserOptions { Vector urls; Vector raw_urls; - URL::URL new_tab_page_url; Vector certificates {}; NewWindow new_window { NewWindow::No }; ForceNewProcess force_new_process { ForceNewProcess::No }; diff --git a/Libraries/LibWebView/SearchEngine.cpp b/Libraries/LibWebView/SearchEngine.cpp index 0d5e9f671fc..ec6a1ec7b59 100644 --- a/Libraries/LibWebView/SearchEngine.cpp +++ b/Libraries/LibWebView/SearchEngine.cpp @@ -28,14 +28,6 @@ ReadonlySpan search_engines() return builtin_search_engines; } -SearchEngine const& default_search_engine() -{ - static auto default_engine = find_search_engine_by_name("Google"sv); - VERIFY(default_engine.has_value()); - - return *default_engine; -} - Optional find_search_engine_by_name(StringView name) { auto it = AK::find_if(builtin_search_engines.begin(), builtin_search_engines.end(), diff --git a/Libraries/LibWebView/SearchEngine.h b/Libraries/LibWebView/SearchEngine.h index c02354c5732..fa5b84b1c44 100644 --- a/Libraries/LibWebView/SearchEngine.h +++ b/Libraries/LibWebView/SearchEngine.h @@ -17,7 +17,6 @@ struct SearchEngine { }; ReadonlySpan search_engines(); -SearchEngine const& default_search_engine(); Optional find_search_engine_by_name(StringView name); Optional find_search_engine_by_query_url(StringView query_url); String format_search_query_for_display(StringView query_url, StringView query); diff --git a/Libraries/LibWebView/Settings.cpp b/Libraries/LibWebView/Settings.cpp new file mode 100644 index 00000000000..7b6b88df39a --- /dev/null +++ b/Libraries/LibWebView/Settings.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WebView { + +static constexpr auto new_tab_page_url_key = "newTabPageURL"sv; +static constexpr auto search_engine_key = "searchEngine"sv; +static constexpr auto search_engine_name_key = "name"sv; + +static ErrorOr read_settings_file(StringView settings_path) +{ + // FIXME: Move this to a generic "Ladybird data directory" helper. + auto settings_directory = ByteString::formatted("{}/Ladybird", Core::StandardPaths::user_data_directory()); + + auto settings_file = Core::File::open(settings_path, Core::File::OpenMode::Read); + if (settings_file.is_error()) { + if (settings_file.error().is_errno() && settings_file.error().code() == ENOENT) + return JsonObject {}; + return settings_file.release_error(); + } + + auto settings_contents = TRY(settings_file.value()->read_until_eof()); + auto settings_json = TRY(JsonValue::from_string(settings_contents)); + + if (!settings_json.is_object()) + return Error::from_string_literal("Expected Ladybird settings to be a JSON object"); + return move(settings_json.as_object()); +} + +static ErrorOr write_settings_file(StringView settings_path, StringView contents) +{ + auto settings_directory = LexicalPath { settings_path }.parent(); + TRY(Core::Directory::create(settings_directory, Core::Directory::CreateDirectories::Yes)); + + auto settings_file = TRY(Core::File::open(settings_path, Core::File::OpenMode::Write)); + TRY(settings_file->write_until_depleted(contents)); + + return {}; +} + +Settings Settings::create(Badge) +{ + auto settings_directory = ByteString::formatted("{}/Ladybird", Core::StandardPaths::user_data_directory()); + auto settings_path = ByteString::formatted("{}/Settings.json", settings_directory); + + Settings settings { move(settings_path) }; + + auto settings_json = read_settings_file(settings.m_settings_path); + if (settings_json.is_error()) { + warnln("Unable to read Ladybird settings: {}", settings_json.error()); + return settings; + } + + if (auto new_tab_page_url = settings_json.value().get_string(new_tab_page_url_key); new_tab_page_url.has_value()) { + if (auto parsed_new_tab_page_url = URL::Parser::basic_parse(*new_tab_page_url); parsed_new_tab_page_url.has_value()) + settings.m_new_tab_page_url = parsed_new_tab_page_url.release_value(); + } + + if (auto search_engine = settings_json.value().get_object(search_engine_key); search_engine.has_value()) { + if (auto search_engine_name = search_engine->get_string(search_engine_name_key); search_engine_name.has_value()) + settings.m_search_engine = find_search_engine_by_name(*search_engine_name); + } + + return settings; +} + +Settings::Settings(ByteString settings_path) + : m_settings_path(move(settings_path)) + , m_new_tab_page_url(URL::about_newtab()) +{ +} + +String Settings::serialize_json() const +{ + StringBuilder builder; + auto serializer = MUST(JsonObjectSerializer<>::try_create(builder)); + + MUST(serializer.add(new_tab_page_url_key, m_new_tab_page_url.serialize())); + + if (m_search_engine.has_value()) { + auto search_engine = MUST(serializer.add_object(search_engine_key)); + MUST(search_engine.add(search_engine_name_key, m_search_engine->name)); + MUST(search_engine.finish()); + } + + MUST(serializer.finish()); + return MUST(builder.to_string()); +} + +void Settings::restore_defaults() +{ + m_new_tab_page_url = URL::about_newtab(); + m_search_engine.clear(); + + persist_settings(); + + for (auto& observer : m_observers) + observer.new_tab_page_url_changed(); +} + +void Settings::set_new_tab_page_url(URL::URL new_tab_page_url) +{ + m_new_tab_page_url = move(new_tab_page_url); + persist_settings(); + + for (auto& observer : m_observers) + observer.new_tab_page_url_changed(); +} + +void Settings::set_search_engine(Optional search_engine_name) +{ + if (search_engine_name.has_value()) + m_search_engine = find_search_engine_by_name(*search_engine_name); + else + m_search_engine.clear(); + + persist_settings(); + + for (auto& observer : m_observers) + observer.search_engine_changed(); +} + +void Settings::persist_settings() +{ + auto settings = serialize_json(); + + if (auto result = write_settings_file(m_settings_path, settings); result.is_error()) + warnln("Unable to persist Ladybird settings: {}", result.error()); +} + +void Settings::add_observer(Badge, SettingsObserver& observer) +{ + Application::settings().m_observers.append(observer); +} + +void Settings::remove_observer(Badge, SettingsObserver& observer) +{ + auto was_removed = Application::settings().m_observers.remove_first_matching([&](auto const& candidate) { + return &candidate == &observer; + }); + VERIFY(was_removed); +} + +SettingsObserver::SettingsObserver() +{ + Settings::add_observer({}, *this); +} + +SettingsObserver::~SettingsObserver() +{ + Settings::remove_observer({}, *this); +} + +} diff --git a/Libraries/LibWebView/Settings.h b/Libraries/LibWebView/Settings.h new file mode 100644 index 00000000000..717dadc69b1 --- /dev/null +++ b/Libraries/LibWebView/Settings.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace WebView { + +class SettingsObserver { +public: + SettingsObserver(); + virtual ~SettingsObserver(); + + virtual void new_tab_page_url_changed() { } + virtual void search_engine_changed() { } +}; + +class Settings { +public: + static Settings create(Badge); + + String serialize_json() const; + + void restore_defaults(); + + URL::URL const& new_tab_page_url() const { return m_new_tab_page_url; } + void set_new_tab_page_url(URL::URL); + + Optional const& search_engine() const { return m_search_engine; } + void set_search_engine(Optional search_engine_name); + + static void add_observer(Badge, SettingsObserver&); + static void remove_observer(Badge, SettingsObserver&); + +private: + explicit Settings(ByteString settings_path); + + void persist_settings(); + + ByteString m_settings_path; + + URL::URL m_new_tab_page_url; + Optional m_search_engine; + + Vector m_observers; +}; + +} diff --git a/UI/AppKit/Application/Application.h b/UI/AppKit/Application/Application.h index 68e41d50275..7bb1736fbb7 100644 --- a/UI/AppKit/Application/Application.h +++ b/UI/AppKit/Application/Application.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, Tim Flynn + * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,7 +9,6 @@ #include #include #include -#include #include #import @@ -20,9 +19,7 @@ class WebViewBridge; @interface Application : NSApplication -- (void)setupWebViewApplication:(Main::Arguments&)arguments - newTabPageURL:(URL::URL)new_tab_page_url; - +- (void)setupWebViewApplication:(Main::Arguments&)arguments; - (ErrorOr)launchServices; @end diff --git a/UI/AppKit/Application/Application.mm b/UI/AppKit/Application/Application.mm index 5b704e49b3e..16c0530192c 100644 --- a/UI/AppKit/Application/Application.mm +++ b/UI/AppKit/Application/Application.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, Tim Flynn + * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -58,9 +58,8 @@ ApplicationBridge::ApplicationBridge(Badge, Main::Argument #pragma mark - Public methods - (void)setupWebViewApplication:(Main::Arguments&)arguments - newTabPageURL:(URL::URL)new_tab_page_url { - m_application_bridge = Ladybird::ApplicationBridge::create(arguments, move(new_tab_page_url)); + m_application_bridge = Ladybird::ApplicationBridge::create(arguments); } - (ErrorOr)launchServices diff --git a/UI/AppKit/Application/ApplicationDelegate.h b/UI/AppKit/Application/ApplicationDelegate.h index 7c44d3b80af..1365efc01f5 100644 --- a/UI/AppKit/Application/ApplicationDelegate.h +++ b/UI/AppKit/Application/ApplicationDelegate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, Tim Flynn + * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -13,7 +13,6 @@ #include #include #include -#include #import @@ -46,6 +45,5 @@ - (Web::CSS::PreferredColorScheme)preferredColorScheme; - (Web::CSS::PreferredContrast)preferredContrast; - (Web::CSS::PreferredMotion)preferredMotion; -- (WebView::SearchEngine const&)searchEngine; @end diff --git a/UI/AppKit/Application/ApplicationDelegate.mm b/UI/AppKit/Application/ApplicationDelegate.mm index 08171aaf352..4e148648bdd 100644 --- a/UI/AppKit/Application/ApplicationDelegate.mm +++ b/UI/AppKit/Application/ApplicationDelegate.mm @@ -6,7 +6,6 @@ #include #include -#include #import #import @@ -27,8 +26,6 @@ Web::CSS::PreferredContrast m_preferred_contrast; Web::CSS::PreferredMotion m_preferred_motion; ByteString m_navigator_compatibility_mode; - - WebView::SearchEngine m_search_engine; } @property (nonatomic, strong) NSMutableArray* managed_tabs; @@ -75,7 +72,6 @@ m_preferred_contrast = Web::CSS::PreferredContrast::Auto; m_preferred_motion = Web::CSS::PreferredMotion::Auto; m_navigator_compatibility_mode = "chrome"; - m_search_engine = WebView::default_search_engine(); // Reduce the tooltip delay, as the default delay feels quite long. [[NSUserDefaults standardUserDefaults] setObject:@100 forKey:@"NSInitialToolTipDelay"]; @@ -158,11 +154,6 @@ return m_preferred_motion; } -- (WebView::SearchEngine const&)searchEngine -{ - return m_search_engine; -} - #pragma mark - Private methods - (void)openAboutVersionPage:(id)sender @@ -383,17 +374,6 @@ } } -- (void)setSearchEngine:(id)sender -{ - auto* item = (NSMenuItem*)sender; - auto title = Ladybird::ns_string_to_string([item title]); - - if (auto search_engine = WebView::find_search_engine_by_name(title); search_engine.has_value()) - m_search_engine = search_engine.release_value(); - else - m_search_engine = WebView::default_search_engine(); -} - - (void)clearHistory:(id)sender { for (TabController* controller in self.managed_tabs) { @@ -590,21 +570,6 @@ auto* menu = [[NSMenuItem alloc] init]; auto* submenu = [[NSMenu alloc] initWithTitle:@"Settings"]; - auto* search_engine_menu = [[NSMenu alloc] init]; - - for (auto const& search_engine : WebView::search_engines()) { - [search_engine_menu addItem:[[NSMenuItem alloc] initWithTitle:Ladybird::string_to_ns_string(search_engine.name) - action:@selector(setSearchEngine:) - keyEquivalent:@""]]; - } - - auto* search_engine_menu_item = [[NSMenuItem alloc] initWithTitle:@"Search Engine" - action:nil - keyEquivalent:@""]; - [search_engine_menu_item setSubmenu:search_engine_menu]; - - [submenu addItem:search_engine_menu_item]; - [submenu addItem:[[NSMenuItem alloc] initWithTitle:@"Enable Autoplay" action:@selector(toggleAutoplay:) keyEquivalent:@""]]; @@ -835,9 +800,6 @@ [item setState:(m_preferred_motion == Web::CSS::PreferredMotion::NoPreference) ? NSControlStateValueOn : NSControlStateValueOff]; } else if ([item action] == @selector(setReducePreferredMotion:)) { [item setState:(m_preferred_motion == Web::CSS::PreferredMotion::Reduce) ? NSControlStateValueOn : NSControlStateValueOff]; - } else if ([item action] == @selector(setSearchEngine:)) { - auto title = Ladybird::ns_string_to_string([item title]); - [item setState:(m_search_engine.name == title) ? NSControlStateValueOn : NSControlStateValueOff]; } return YES; diff --git a/UI/AppKit/Interface/LadybirdWebView.mm b/UI/AppKit/Interface/LadybirdWebView.mm index 1d94b306e83..0cccff0292e 100644 --- a/UI/AppKit/Interface/LadybirdWebView.mm +++ b/UI/AppKit/Interface/LadybirdWebView.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, Tim Flynn + * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -628,15 +628,15 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ } auto* search_selected_text_menu_item = [self.page_context_menu itemWithTag:CONTEXT_MENU_SEARCH_SELECTED_TEXT_TAG]; - auto selected_text = self.observer + auto const& search_engine = WebView::Application::settings().search_engine(); + + auto selected_text = self.observer && search_engine.has_value() ? m_web_view_bridge->selected_text_with_whitespace_collapsed() : OptionalNone {}; TemporaryChange change_url { m_context_menu_search_text, move(selected_text) }; if (m_context_menu_search_text.has_value()) { - auto* delegate = (ApplicationDelegate*)[NSApp delegate]; - auto action_text = WebView::format_search_query_for_display([delegate searchEngine].query_url, *m_context_menu_search_text); - + auto action_text = WebView::format_search_query_for_display(search_engine->query_url, *m_context_menu_search_text); [search_selected_text_menu_item setTitle:Ladybird::string_to_ns_string(action_text)]; [search_selected_text_menu_item setHidden:NO]; } else { @@ -1136,9 +1136,11 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ - (void)searchSelectedText:(id)sender { - auto* delegate = (ApplicationDelegate*)[NSApp delegate]; + auto const& search_engine = WebView::Application::settings().search_engine(); + if (!search_engine.has_value()) + return; - auto url_string = MUST(String::formatted([delegate searchEngine].query_url, URL::percent_encode(*m_context_menu_search_text))); + auto url_string = MUST(String::formatted(search_engine->query_url, URL::percent_encode(*m_context_menu_search_text))); auto url = URL::Parser::basic_parse(url_string); VERIFY(url.has_value()); [self.observer onCreateNewTab:url.release_value() activateTab:Web::HTML::ActivateTab::Yes]; diff --git a/UI/AppKit/Interface/TabController.mm b/UI/AppKit/Interface/TabController.mm index 3895687cb58..b6f0e36164c 100644 --- a/UI/AppKit/Interface/TabController.mm +++ b/UI/AppKit/Interface/TabController.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, Tim Flynn + * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -234,7 +234,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde self.tab.titlebarAppearsTransparent = NO; - [delegate createNewTab:WebView::Application::browser_options().new_tab_page_url + [delegate createNewTab:WebView::Application::settings().new_tab_page_url() fromTab:[self tab] activateTab:Web::HTML::ActivateTab::Yes]; @@ -705,9 +705,12 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde } auto url_string = Ladybird::ns_string_to_string([[text_view textStorage] string]); - auto* delegate = (ApplicationDelegate*)[NSApp delegate]; - if (auto url = WebView::sanitize_url(url_string, [delegate searchEngine].query_url); url.has_value()) { + Optional search_engine_url; + if (auto const& search_engine = WebView::Application::settings().search_engine(); search_engine.has_value()) + search_engine_url = search_engine->query_url; + + if (auto url = WebView::sanitize_url(url_string, search_engine_url); url.has_value()) { [self loadURL:*url]; } diff --git a/UI/AppKit/main.mm b/UI/AppKit/main.mm index 93d826b1022..37d2cced577 100644 --- a/UI/AppKit/main.mm +++ b/UI/AppKit/main.mm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2024, Tim Flynn + * Copyright (c) 2023-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,11 +12,11 @@ #include #include #include +#include #include #include #include #include -#include #import #import @@ -50,9 +50,8 @@ ErrorOr serenity_main(Main::Arguments arguments) Application* application = [Application sharedApplication]; Core::EventLoopManager::install(*new WebView::EventLoopManagerMacOS); - auto url = URL::Parser::basic_parse(Browser::default_new_tab_url); - VERIFY(url.has_value()); - [application setupWebViewApplication:arguments newTabPageURL:url.release_value()]; + + [application setupWebViewApplication:arguments]; WebView::platform_init(); diff --git a/UI/DefaultSettings.h b/UI/DefaultSettings.h deleted file mode 100644 index 8e970385d40..00000000000 --- a/UI/DefaultSettings.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2023, Ben Wiederhake - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Browser { - -static constexpr StringView default_homepage_url = "resource://html/misc/welcome.html"sv; -static constexpr StringView default_new_tab_url = "about:newtab"sv; -static constexpr StringView default_color_scheme = "auto"sv; -static constexpr bool default_enable_content_filters = true; -static constexpr bool default_show_bookmarks_bar = true; -static constexpr bool default_close_download_widget_on_finish = false; -static constexpr bool default_allow_autoplay_on_all_websites = false; - -} diff --git a/UI/Headless/main.cpp b/UI/Headless/main.cpp index b32846d755b..11d72dad1b1 100644 --- a/UI/Headless/main.cpp +++ b/UI/Headless/main.cpp @@ -63,7 +63,7 @@ ErrorOr serenity_main(Main::Arguments arguments) { WebView::platform_init(); - auto app = Ladybird::Application::create(arguments, URL::about_newtab()); + auto app = Ladybird::Application::create(arguments); TRY(app->launch_services()); Core::ResourceImplementation::install(make(MUST(String::from_byte_string(app->resources_folder)))); diff --git a/UI/Qt/BrowserWindow.cpp b/UI/Qt/BrowserWindow.cpp index 0c21a12d1e4..11cce413445 100644 --- a/UI/Qt/BrowserWindow.cpp +++ b/UI/Qt/BrowserWindow.cpp @@ -633,9 +633,7 @@ BrowserWindow::BrowserWindow(Vector const& initial_urls, IsPopupWindow QObject::connect(quit_action, &QAction::triggered, this, &QMainWindow::close); QObject::connect(m_new_tab_action, &QAction::triggered, this, [this] { - auto url = ak_url_from_qstring(Settings::the()->new_tab_page()); - VERIFY(url.has_value()); - auto& tab = new_tab_from_url(url.release_value(), Web::HTML::ActivateTab::Yes); + auto& tab = new_tab_from_url(WebView::Application::settings().new_tab_page_url(), Web::HTML::ActivateTab::Yes); tab.set_url_is_hidden(true); tab.focus_location_editor(); }); diff --git a/UI/Qt/LocationEdit.cpp b/UI/Qt/LocationEdit.cpp index e7f41493376..11eb2aeec50 100644 --- a/UI/Qt/LocationEdit.cpp +++ b/UI/Qt/LocationEdit.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -21,8 +22,6 @@ LocationEdit::LocationEdit(QWidget* parent) : QLineEdit(parent) { update_placeholder(); - QObject::connect(Settings::the(), &Settings::enable_search_changed, this, &LocationEdit::update_placeholder); - QObject::connect(Settings::the(), &Settings::search_engine_changed, this, &LocationEdit::update_placeholder); m_autocomplete = make(this); this->setCompleter(m_autocomplete); @@ -38,8 +37,8 @@ LocationEdit::LocationEdit(QWidget* parent) clearFocus(); Optional search_engine_url; - if (Settings::the()->enable_search()) - search_engine_url = Settings::the()->search_engine().query_url; + if (auto const& search_engine = WebView::Application::settings().search_engine(); search_engine.has_value()) + search_engine_url = search_engine->query_url; auto query = ak_string_from_qstring(text()); @@ -87,14 +86,19 @@ void LocationEdit::focusOutEvent(QFocusEvent* event) } } +void LocationEdit::search_engine_changed() +{ + update_placeholder(); +} + void LocationEdit::update_placeholder() { - if (Settings::the()->enable_search()) - setPlaceholderText(qstring_from_ak_string( - MUST(String::formatted("Search with {} or enter web address", - Settings::the()->search_engine().name)))); - else + if (auto const& search_engine = WebView::Application::settings().search_engine(); search_engine.has_value()) { + auto prompt = MUST(String::formatted("Search with {} or enter web address", search_engine->name)); + setPlaceholderText(qstring_from_ak_string(prompt)); + } else { setPlaceholderText("Enter web address"); + } } void LocationEdit::highlight_location() diff --git a/UI/Qt/LocationEdit.h b/UI/Qt/LocationEdit.h index c99b28564a6..bc8f51ca8c7 100644 --- a/UI/Qt/LocationEdit.h +++ b/UI/Qt/LocationEdit.h @@ -7,14 +7,18 @@ #pragma once #include +#include #include #include namespace Ladybird { -class LocationEdit final : public QLineEdit { +class LocationEdit final + : public QLineEdit + , public WebView::SettingsObserver { Q_OBJECT + public: explicit LocationEdit(QWidget*); @@ -28,6 +32,8 @@ private: virtual void focusInEvent(QFocusEvent* event) override; virtual void focusOutEvent(QFocusEvent* event) override; + virtual void search_engine_changed() override; + void update_placeholder(); void highlight_location(); AK::OwnPtr m_autocomplete; diff --git a/UI/Qt/Settings.cpp b/UI/Qt/Settings.cpp index 7403d502744..4126da6270d 100644 --- a/UI/Qt/Settings.cpp +++ b/UI/Qt/Settings.cpp @@ -7,27 +7,14 @@ */ #include -#include #include #include namespace Ladybird { Settings::Settings() - : m_search_engine(WebView::default_search_engine()) { m_qsettings = make(QSettings::IniFormat, QSettings::UserScope, "Ladybird", "Ladybird", this); - - auto default_search_engine = WebView::default_search_engine(); - auto default_search_engine_name = qstring_from_ak_string(default_search_engine.name); - - auto search_engine_name = m_qsettings->value("search_engine_name", default_search_engine_name).toString(); - auto search_engine = WebView::find_search_engine_by_name(ak_string_from_qstring(search_engine_name)); - - if (search_engine.has_value()) - m_search_engine = search_engine.release_value(); - else - set_search_engine(move(default_search_engine)); } ByteString Settings::directory() @@ -67,13 +54,6 @@ void Settings::set_is_maximized(bool is_maximized) m_qsettings->setValue("is_maximized", is_maximized); } -void Settings::set_search_engine(WebView::SearchEngine search_engine) -{ - m_qsettings->setValue("search_engine_name", qstring_from_ak_string(search_engine.name)); - m_search_engine = move(search_engine); - emit search_engine_changed(m_search_engine); -} - QStringList Settings::preferred_languages() { return m_qsettings->value("preferred_languages").toStringList(); @@ -99,17 +79,6 @@ void Settings::set_autocomplete_engine(EngineProvider const& engine_provider) m_qsettings->setValue("autocomplete_engine", engine_provider.url); } -QString Settings::new_tab_page() -{ - static auto const default_new_tab_url = qstring_from_ak_string(Browser::default_new_tab_url); - return m_qsettings->value("new_tab_page", default_new_tab_url).toString(); -} - -void Settings::set_new_tab_page(QString const& page) -{ - m_qsettings->setValue("new_tab_page", page); -} - bool Settings::enable_autocomplete() { return m_qsettings->value("enable_autocomplete", false).toBool(); @@ -120,17 +89,6 @@ void Settings::set_enable_autocomplete(bool enable) m_qsettings->setValue("enable_autocomplete", enable); } -bool Settings::enable_search() -{ - return m_qsettings->value("enable_search", false).toBool(); -} - -void Settings::set_enable_search(bool enable) -{ - m_qsettings->setValue("enable_search", enable); - emit enable_search_changed(enable); -} - bool Settings::enable_do_not_track() { return m_qsettings->value("enable_do_not_track", false).toBool(); diff --git a/UI/Qt/Settings.h b/UI/Qt/Settings.h index 38f73dd6293..520dbac5470 100644 --- a/UI/Qt/Settings.h +++ b/UI/Qt/Settings.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -42,12 +41,6 @@ public: bool is_maximized(); void set_is_maximized(bool is_maximized); - QString new_tab_page(); - void set_new_tab_page(QString const& page); - - WebView::SearchEngine search_engine() const { return m_search_engine; } - void set_search_engine(WebView::SearchEngine engine); - QStringList preferred_languages(); void set_preferred_languages(QStringList const& languages); @@ -55,16 +48,12 @@ public: QString name; QString url; }; - EngineProvider autocomplete_engine(); void set_autocomplete_engine(EngineProvider const& engine); bool enable_autocomplete(); void set_enable_autocomplete(bool enable); - bool enable_search(); - void set_enable_search(bool enable); - bool enable_do_not_track(); void set_enable_do_not_track(bool enable); @@ -76,8 +65,6 @@ public: signals: void show_menubar_changed(bool show_menubar); - void enable_search_changed(bool enable); - void search_engine_changed(WebView::SearchEngine engine); void preferred_languages_changed(QStringList const& languages); void enable_do_not_track_changed(bool enable); void enable_autoplay_changed(bool enable); @@ -87,7 +74,6 @@ protected: private: OwnPtr m_qsettings; - WebView::SearchEngine m_search_engine; }; } diff --git a/UI/Qt/SettingsDialog.cpp b/UI/Qt/SettingsDialog.cpp index 104a1ae96cd..f69cb1aec28 100644 --- a/UI/Qt/SettingsDialog.cpp +++ b/UI/Qt/SettingsDialog.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -24,13 +23,6 @@ SettingsDialog::SettingsDialog(QMainWindow* window) { m_layout = new QFormLayout(this); - m_enable_search = new QCheckBox(this); - m_enable_search->setChecked(Settings::the()->enable_search()); - - m_search_engine_dropdown = new QPushButton(this); - m_search_engine_dropdown->setText(qstring_from_ak_string(Settings::the()->search_engine().name)); - m_search_engine_dropdown->setMaximumWidth(200); - m_preferred_languages = new QLineEdit(this); m_preferred_languages->setText(Settings::the()->preferred_languages().join(",")); QObject::connect(m_preferred_languages, &QLineEdit::editingFinished, this, [this] { @@ -47,21 +39,6 @@ SettingsDialog::SettingsDialog(QMainWindow* window) m_autocomplete_engine_dropdown->setText(Settings::the()->autocomplete_engine().name); m_autocomplete_engine_dropdown->setMaximumWidth(200); - m_new_tab_page = new QLineEdit(this); - m_new_tab_page->setText(Settings::the()->new_tab_page()); - QObject::connect(m_new_tab_page, &QLineEdit::textChanged, this, [this] { - auto url_string = ak_string_from_qstring(m_new_tab_page->text()); - m_new_tab_page->setStyleSheet(URL::Parser::basic_parse(url_string).has_value() ? "" : "border: 1px solid red;"); - }); - QObject::connect(m_new_tab_page, &QLineEdit::editingFinished, this, [this] { - auto url_string = ak_string_from_qstring(m_new_tab_page->text()); - if (URL::Parser::basic_parse(url_string).has_value()) - Settings::the()->set_new_tab_page(m_new_tab_page->text()); - }); - QObject::connect(m_new_tab_page, &QLineEdit::returnPressed, this, [this] { - close(); - }); - m_enable_do_not_track = new QCheckBox(this); m_enable_do_not_track->setChecked(Settings::the()->enable_do_not_track()); #if (QT_VERSION > QT_VERSION_CHECK(6, 7, 0)) @@ -87,11 +64,8 @@ SettingsDialog::SettingsDialog(QMainWindow* window) Settings::the()->set_enable_autoplay(state == Qt::Checked); }); - setup_search_engines(); + setup_autocomplete_engine(); - m_layout->addRow(new QLabel("Page on New Tab", this), m_new_tab_page); - m_layout->addRow(new QLabel("Enable Search", this), m_enable_search); - m_layout->addRow(new QLabel("Search Engine", this), m_search_engine_dropdown); m_layout->addRow(new QLabel("Preferred Language(s)", this), m_preferred_languages); m_layout->addRow(new QLabel("Enable Autocomplete", this), m_enable_autocomplete); m_layout->addRow(new QLabel("Autocomplete Engine", this), m_autocomplete_engine_dropdown); @@ -103,7 +77,7 @@ SettingsDialog::SettingsDialog(QMainWindow* window) resize(600, 250); } -void SettingsDialog::setup_search_engines() +void SettingsDialog::setup_autocomplete_engine() { // FIXME: These should be centralized in LibWebView. Vector autocomplete_engines = { @@ -112,21 +86,6 @@ void SettingsDialog::setup_search_engines() { "Yahoo", "https://search.yahoo.com/sugg/gossip/gossip-us-ura/?output=sd1&command={}" }, }; - QMenu* search_engine_menu = new QMenu(this); - for (auto const& search_engine : WebView::search_engines()) { - auto search_engine_name = qstring_from_ak_string(search_engine.name); - QAction* action = new QAction(search_engine_name, this); - - connect(action, &QAction::triggered, this, [&, search_engine_name = std::move(search_engine_name)]() { - Settings::the()->set_search_engine(search_engine); - m_search_engine_dropdown->setText(search_engine_name); - }); - - search_engine_menu->addAction(action); - } - m_search_engine_dropdown->setMenu(search_engine_menu); - m_search_engine_dropdown->setEnabled(Settings::the()->enable_search()); - QMenu* autocomplete_engine_menu = new QMenu(this); for (auto& autocomplete_engine : autocomplete_engines) { QAction* action = new QAction(autocomplete_engine.name, this); @@ -139,15 +98,6 @@ void SettingsDialog::setup_search_engines() m_autocomplete_engine_dropdown->setMenu(autocomplete_engine_menu); m_autocomplete_engine_dropdown->setEnabled(Settings::the()->enable_autocomplete()); -#if (QT_VERSION > QT_VERSION_CHECK(6, 7, 0)) - connect(m_enable_search, &QCheckBox::checkStateChanged, this, [&](int state) { -#else - connect(m_enable_search, &QCheckBox::stateChanged, this, [&](int state) { -#endif - Settings::the()->set_enable_search(state == Qt::Checked); - m_search_engine_dropdown->setEnabled(state == Qt::Checked); - }); - #if (QT_VERSION > QT_VERSION_CHECK(6, 7, 0)) connect(m_enable_autocomplete, &QCheckBox::checkStateChanged, this, [&](int state) { #else diff --git a/UI/Qt/SettingsDialog.h b/UI/Qt/SettingsDialog.h index 623b2b8d98b..461dd23e71d 100644 --- a/UI/Qt/SettingsDialog.h +++ b/UI/Qt/SettingsDialog.h @@ -5,6 +5,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#pragma once + #include #include #include @@ -12,8 +14,6 @@ #include #include -#pragma once - namespace Ladybird { class SettingsDialog : public QDialog { @@ -23,13 +23,10 @@ public: explicit SettingsDialog(QMainWindow* window); private: - void setup_search_engines(); + void setup_autocomplete_engine(); QFormLayout* m_layout; QMainWindow* m_window { nullptr }; - QLineEdit* m_new_tab_page { nullptr }; - QCheckBox* m_enable_search { nullptr }; - QPushButton* m_search_engine_dropdown { nullptr }; QLineEdit* m_preferred_languages { nullptr }; QCheckBox* m_enable_autocomplete { nullptr }; QPushButton* m_autocomplete_engine_dropdown { nullptr }; diff --git a/UI/Qt/Tab.cpp b/UI/Qt/Tab.cpp index 1851f683a4e..730c34d599a 100644 --- a/UI/Qt/Tab.cpp +++ b/UI/Qt/Tab.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -454,9 +455,14 @@ Tab::Tab(BrowserWindow* window, RefPtr parent_client, auto* search_selected_text_action = new QAction("&Search for ", this); search_selected_text_action->setIcon(load_icon_from_uri("resource://icons/16x16/find.png"sv)); QObject::connect(search_selected_text_action, &QAction::triggered, this, [this]() { - auto url_string = MUST(String::formatted(Settings::the()->search_engine().query_url, URL::percent_encode(*m_page_context_menu_search_text))); + auto const& search_engine = WebView::Application::settings().search_engine(); + if (!search_engine.has_value()) + return; + + auto url_string = MUST(String::formatted(search_engine->query_url, URL::percent_encode(*m_page_context_menu_search_text))); auto url = URL::Parser::basic_parse(url_string); VERIFY(url.has_value()); + m_window->new_tab_from_url(url.release_value(), Web::HTML::ActivateTab::Yes); }); @@ -517,13 +523,15 @@ Tab::Tab(BrowserWindow* window, RefPtr parent_client, m_page_context_menu->addAction(&m_window->view_source_action()); view().on_context_menu_request = [this, search_selected_text_action](Gfx::IntPoint content_position) { - auto selected_text = Settings::the()->enable_search() + auto const& search_engine = WebView::Application::settings().search_engine(); + + auto selected_text = search_engine.has_value() ? view().selected_text_with_whitespace_collapsed() : OptionalNone {}; - TemporaryChange change_url { m_page_context_menu_search_text, std::move(selected_text) }; + TemporaryChange change_url { m_page_context_menu_search_text, AK::move(selected_text) }; if (m_page_context_menu_search_text.has_value()) { - auto action_text = WebView::format_search_query_for_display(Settings::the()->search_engine().query_url, *m_page_context_menu_search_text); + auto action_text = WebView::format_search_query_for_display(search_engine->query_url, *m_page_context_menu_search_text); search_selected_text_action->setText(qstring_from_ak_string(action_text)); search_selected_text_action->setVisible(true); } else { diff --git a/UI/Qt/main.cpp b/UI/Qt/main.cpp index 2bb63bf03b1..1aba5f6559d 100644 --- a/UI/Qt/main.cpp +++ b/UI/Qt/main.cpp @@ -73,9 +73,7 @@ ErrorOr serenity_main(Main::Arguments arguments) Core::EventLoopManager::install(*new WebView::EventLoopManagerQt); - auto url = ak_url_from_qstring(Ladybird::Settings::the()->new_tab_page()); - VERIFY(url.has_value()); - auto app = Ladybird::Application::create(arguments, url.release_value()); + auto app = Ladybird::Application::create(arguments); static_cast(Core::EventLoop::current().impl()).set_main_loop(); TRY(handle_attached_debugger());