From c75e40180ca19bc638b015741c31742023974d68 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 24 Mar 2025 09:50:12 -0400 Subject: [PATCH] LibWeb+LibWebView+WebContent: Convert about:processes to a WebUI --- Base/res/ladybird/about-pages/processes.html | 42 +++++++++++--------- Libraries/LibWeb/CMakeLists.txt | 1 - Libraries/LibWeb/Forward.h | 1 - Libraries/LibWeb/HTML/Window.cpp | 5 +-- Libraries/LibWeb/Internals/Processes.cpp | 35 ---------------- Libraries/LibWeb/Internals/Processes.h | 28 ------------- Libraries/LibWeb/Internals/Processes.idl | 4 -- Libraries/LibWeb/Page/Page.h | 2 - Libraries/LibWeb/idl_files.cmake | 1 - Libraries/LibWebView/Application.cpp | 13 ------ Libraries/LibWebView/Application.h | 4 +- Libraries/LibWebView/CMakeLists.txt | 1 + Libraries/LibWebView/ProcessManager.cpp | 25 +++++------- Libraries/LibWebView/ProcessManager.h | 3 +- Libraries/LibWebView/WebContentClient.cpp | 6 --- Libraries/LibWebView/WebContentClient.h | 1 - Libraries/LibWebView/WebUI.cpp | 6 ++- Libraries/LibWebView/WebUI/ProcessesUI.cpp | 28 +++++++++++++ Libraries/LibWebView/WebUI/ProcessesUI.h | 22 ++++++++++ Services/WebContent/PageClient.cpp | 5 --- Services/WebContent/PageClient.h | 1 - Services/WebContent/WebContentClient.ipc | 2 - 22 files changed, 96 insertions(+), 140 deletions(-) delete mode 100644 Libraries/LibWeb/Internals/Processes.cpp delete mode 100644 Libraries/LibWeb/Internals/Processes.h delete mode 100644 Libraries/LibWeb/Internals/Processes.idl create mode 100644 Libraries/LibWebView/WebUI/ProcessesUI.cpp create mode 100644 Libraries/LibWebView/WebUI/ProcessesUI.h diff --git a/Base/res/ladybird/about-pages/processes.html b/Base/res/ladybird/about-pages/processes.html index 6d630831e1f..b311178d856 100644 --- a/Base/res/ladybird/about-pages/processes.html +++ b/Base/res/ladybird/about-pages/processes.html @@ -97,9 +97,9 @@ descending: 2, }); - processes.processes = []; - processes.sortDirection = Direction.ascending; - processes.sortKey = "pid"; + window.processes = []; + window.sortDirection = Direction.ascending; + window.sortKey = "pid"; const renderSortedProcesses = () => { document.querySelectorAll("th").forEach(header => { @@ -107,17 +107,17 @@ header.classList.remove("sorted-descending"); }); - if (processes.sortDirection === Direction.ascending) { - document.getElementById(processes.sortKey).classList.add("sorted-ascending"); + if (window.sortDirection === Direction.ascending) { + document.getElementById(window.sortKey).classList.add("sorted-ascending"); } else { - document.getElementById(processes.sortKey).classList.add("sorted-descending"); + document.getElementById(window.sortKey).classList.add("sorted-descending"); } - const multiplier = processes.sortDirection === Direction.ascending ? 1 : -1; + const multiplier = window.sortDirection === Direction.ascending ? 1 : -1; - processes.processes.sort((lhs, rhs) => { - const lhsValue = lhs[processes.sortKey]; - const rhsValue = rhs[processes.sortKey]; + window.processes.sort((lhs, rhs) => { + const lhsValue = lhs[window.sortKey]; + const rhsValue = rhs[window.sortKey]; if (typeof lhsValue === "string") { return multiplier * lhsValue.localeCompare(rhsValue); @@ -136,7 +136,7 @@ column.innerText = value; }; - processes.processes.forEach(process => { + window.processes.forEach(process => { let row = newTable.insertRow(); insertColumn(row, process.name); insertColumn(row, process.pid); @@ -147,28 +147,34 @@ oldTable.parentNode.replaceChild(newTable, oldTable); }; - processes.loadProcessStatistics = statistics => { - processes.processes = JSON.parse(statistics); + const loadProcessStatistics = processes => { + window.processes = processes; renderSortedProcesses(); }; - document.addEventListener("DOMContentLoaded", () => { + document.addEventListener("WebUILoaded", () => { document.querySelectorAll("th").forEach(header => { header.addEventListener("click", () => { - processes.sortDirection = header.classList.contains("sorted-descending") + window.sortDirection = header.classList.contains("sorted-descending") ? Direction.ascending : Direction.descending; - processes.sortKey = header.getAttribute("id"); + window.sortKey = header.getAttribute("id"); renderSortedProcesses(); }); }); setInterval(() => { - processes.updateProcessStatistics(); + ladybird.sendMessage("updateProcessStatistics"); }, 1000); - processes.updateProcessStatistics(); + ladybird.sendMessage("updateProcessStatistics"); + }); + + document.addEventListener("WebUIMessage", event => { + if (event.detail.name === "loadProcessStatistics") { + loadProcessStatistics(event.detail.data); + } }); diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 49698ff26d4..c1a1ad92a9b 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -566,7 +566,6 @@ set(SOURCES Internals/InternalAnimationTimeline.cpp Internals/Internals.cpp Internals/InternalsBase.cpp - Internals/Processes.cpp Internals/Settings.cpp Internals/WebUI.cpp IntersectionObserver/IntersectionObserver.cpp diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 6f890896e09..f25a6cf5a4c 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -627,7 +627,6 @@ class RequestList; namespace Web::Internals { class Internals; -class Processes; class WebUI; } diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp index baa1c762bde..2309faba792 100644 --- a/Libraries/LibWeb/HTML/Window.cpp +++ b/Libraries/LibWeb/HTML/Window.cpp @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -740,9 +739,7 @@ WebIDL::ExceptionOr Window::initialize_web_interfaces(Badge(realm), JS::default_attributes); - else if (path == "settings"sv) + if (path == "settings"sv) define_direct_property("settings"_fly_string, realm.create(realm), JS::default_attributes); } diff --git a/Libraries/LibWeb/Internals/Processes.cpp b/Libraries/LibWeb/Internals/Processes.cpp deleted file mode 100644 index 09cd2d71c65..00000000000 --- a/Libraries/LibWeb/Internals/Processes.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2025, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -namespace Web::Internals { - -GC_DEFINE_ALLOCATOR(Processes); - -Processes::Processes(JS::Realm& realm) - : InternalsBase(realm) -{ -} - -Processes::~Processes() = default; - -void Processes::initialize(JS::Realm& realm) -{ - Base::initialize(realm); - WEB_SET_PROTOTYPE_FOR_INTERFACE(Processes); -} - -void Processes::update_process_statistics() -{ - page().client().update_process_statistics(); -} - -} diff --git a/Libraries/LibWeb/Internals/Processes.h b/Libraries/LibWeb/Internals/Processes.h deleted file mode 100644 index 2fcbea7b0bb..00000000000 --- a/Libraries/LibWeb/Internals/Processes.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2025, Tim Flynn - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Web::Internals { - -class Processes final : public InternalsBase { - WEB_PLATFORM_OBJECT(Processes, InternalsBase); - GC_DECLARE_ALLOCATOR(Processes); - -public: - virtual ~Processes() override; - - void update_process_statistics(); - -private: - explicit Processes(JS::Realm&); - - virtual void initialize(JS::Realm&) override; -}; - -} diff --git a/Libraries/LibWeb/Internals/Processes.idl b/Libraries/LibWeb/Internals/Processes.idl deleted file mode 100644 index 9be603113f2..00000000000 --- a/Libraries/LibWeb/Internals/Processes.idl +++ /dev/null @@ -1,4 +0,0 @@ -[Exposed=Nobody] -interface Processes { - undefined updateProcessStatistics(); -}; diff --git a/Libraries/LibWeb/Page/Page.h b/Libraries/LibWeb/Page/Page.h index d08ba7e6ddd..63505702742 100644 --- a/Libraries/LibWeb/Page/Page.h +++ b/Libraries/LibWeb/Page/Page.h @@ -402,8 +402,6 @@ public: virtual void received_message_from_web_ui([[maybe_unused]] String const& name, [[maybe_unused]] JS::Value data) { } - virtual void update_process_statistics() { } - virtual void request_current_settings() { } virtual void restore_default_settings() { } virtual void set_new_tab_page_url(URL::URL const&) { } diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 33ca0e21bcd..d7e62d1f788 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -266,7 +266,6 @@ libweb_js_bindings(IndexedDB/IDBTransaction) libweb_js_bindings(IndexedDB/IDBVersionChangeEvent) libweb_js_bindings(Internals/InternalAnimationTimeline) libweb_js_bindings(Internals/Internals) -libweb_js_bindings(Internals/Processes) libweb_js_bindings(Internals/Settings) libweb_js_bindings(Internals/WebUI) libweb_js_bindings(IntersectionObserver/IntersectionObserver) diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index b86f909a800..29d1a1c1160 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -324,19 +324,6 @@ Optional Application::find_process(pid_t pid) return m_process_manager.find_process(pid); } -void Application::send_updated_process_statistics_to_view(ViewImplementation& view) -{ - m_process_manager.update_all_process_statistics(); - auto statistics = m_process_manager.serialize_json(); - - StringBuilder builder; - builder.append("processes.loadProcessStatistics(\""sv); - builder.append_escaped_for_json(statistics); - builder.append("\");"sv); - - view.run_javascript(MUST(builder.to_string())); -} - void Application::send_current_settings_to_view(ViewImplementation& view) { auto settings = m_settings.serialize_json(); diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index 64d959ead1a..b3a77f7c94a 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -46,6 +46,8 @@ public: static CookieJar& cookie_jar() { return *the().m_cookie_jar; } + static ProcessManager& process_manager() { return the().m_process_manager; } + Core::EventLoop& event_loop() { return m_event_loop; } ErrorOr> launch_web_content_process(ViewImplementation&); @@ -59,8 +61,6 @@ public: #endif Optional find_process(pid_t); - void send_updated_process_statistics_to_view(ViewImplementation&); - void send_current_settings_to_view(ViewImplementation&); void send_available_search_engines_to_view(ViewImplementation&); diff --git a/Libraries/LibWebView/CMakeLists.txt b/Libraries/LibWebView/CMakeLists.txt index c69ad93d447..9a90e8a6d7f 100644 --- a/Libraries/LibWebView/CMakeLists.txt +++ b/Libraries/LibWebView/CMakeLists.txt @@ -25,6 +25,7 @@ set(SOURCES ViewImplementation.cpp WebContentClient.cpp WebUI.cpp + WebUI/ProcessesUI.cpp ) if (APPLE) diff --git a/Libraries/LibWebView/ProcessManager.cpp b/Libraries/LibWebView/ProcessManager.cpp index 10e1b41c188..24928d5e78f 100644 --- a/Libraries/LibWebView/ProcessManager.cpp +++ b/Libraries/LibWebView/ProcessManager.cpp @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include +#include +#include #include #include #include @@ -126,12 +126,10 @@ void ProcessManager::update_all_process_statistics() (void)update_process_statistics(m_statistics); } -String ProcessManager::serialize_json() +JsonValue ProcessManager::serialize_json() { Threading::MutexLocker locker { m_lock }; - - StringBuilder builder; - auto serializer = MUST(JsonArraySerializer<>::try_create(builder)); + JsonArray serialized; m_statistics.for_each_process([&](auto const& process) { auto& process_handle = find_process(process.pid).value(); @@ -143,16 +141,15 @@ String ProcessManager::serialize_json() ? MUST(String::formatted("{} - {}", type, *title)) : String::from_utf8_without_validation(type.bytes()); - auto object = MUST(serializer.add_object()); - MUST(object.add("name"sv, move(process_name))); - MUST(object.add("pid"sv, process.pid)); - MUST(object.add("cpu"sv, process.cpu_percent)); - MUST(object.add("memory"sv, process.memory_usage_bytes)); - MUST(object.finish()); + JsonObject object; + object.set("name"sv, move(process_name)); + object.set("pid"sv, process.pid); + object.set("cpu"sv, process.cpu_percent); + object.set("memory"sv, process.memory_usage_bytes); + serialized.must_append(move(object)); }); - MUST(serializer.finish()); - return MUST(builder.to_string()); + return serialized; } } diff --git a/Libraries/LibWebView/ProcessManager.h b/Libraries/LibWebView/ProcessManager.h index f501718f129..a4c63821100 100644 --- a/Libraries/LibWebView/ProcessManager.h +++ b/Libraries/LibWebView/ProcessManager.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -34,7 +35,7 @@ public: #endif void update_all_process_statistics(); - String serialize_json(); + JsonValue serialize_json(); Function on_process_exited; diff --git a/Libraries/LibWebView/WebContentClient.cpp b/Libraries/LibWebView/WebContentClient.cpp index 3a9792fe7c4..93e006ce54e 100644 --- a/Libraries/LibWebView/WebContentClient.cpp +++ b/Libraries/LibWebView/WebContentClient.cpp @@ -669,12 +669,6 @@ Messages::WebContentClient::RequestWorkerAgentResponse WebContentClient::request return IPC::File {}; } -void WebContentClient::update_process_statistics(u64 page_id) -{ - if (auto view = view_for_page_id(page_id); view.has_value()) - WebView::Application::the().send_updated_process_statistics_to_view(*view); -} - void WebContentClient::request_current_settings(u64 page_id) { if (auto view = view_for_page_id(page_id); view.has_value()) diff --git a/Libraries/LibWebView/WebContentClient.h b/Libraries/LibWebView/WebContentClient.h index 4025508b903..38fa2504d19 100644 --- a/Libraries/LibWebView/WebContentClient.h +++ b/Libraries/LibWebView/WebContentClient.h @@ -130,7 +130,6 @@ private: virtual void did_update_navigation_buttons_state(u64 page_id, bool back_enabled, bool forward_enabled) override; virtual void did_allocate_backing_stores(u64 page_id, i32 front_bitmap_id, Gfx::ShareableBitmap, i32 back_bitmap_id, Gfx::ShareableBitmap) override; virtual Messages::WebContentClient::RequestWorkerAgentResponse request_worker_agent(u64 page_id) override; - virtual void update_process_statistics(u64 page_id) override; virtual void request_current_settings(u64 page_id) override; virtual void restore_default_settings(u64 page_id) override; virtual void set_new_tab_page_url(u64 page_id, URL::URL new_tab_page_url) override; diff --git a/Libraries/LibWebView/WebUI.cpp b/Libraries/LibWebView/WebUI.cpp index 9806b35fcd2..4d2bf33ffe4 100644 --- a/Libraries/LibWebView/WebUI.cpp +++ b/Libraries/LibWebView/WebUI.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace WebView { @@ -31,10 +32,13 @@ static ErrorOr> create_web_ui(WebContentClient& client, return web_ui; } -ErrorOr> WebUI::create(WebContentClient&, String) +ErrorOr> WebUI::create(WebContentClient& client, String host) { RefPtr web_ui; + if (host == "processes"sv) + web_ui = TRY(create_web_ui(client, move(host))); + if (web_ui) web_ui->register_interfaces(); diff --git a/Libraries/LibWebView/WebUI/ProcessesUI.cpp b/Libraries/LibWebView/WebUI/ProcessesUI.cpp new file mode 100644 index 00000000000..f8e9c433169 --- /dev/null +++ b/Libraries/LibWebView/WebUI/ProcessesUI.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace WebView { + +void ProcessesUI::register_interfaces() +{ + register_interface("updateProcessStatistics"sv, [this](auto const&) { + update_process_statistics(); + }); +} + +void ProcessesUI::update_process_statistics() +{ + auto& process_manager = Application::process_manager(); + process_manager.update_all_process_statistics(); + + async_send_message("loadProcessStatistics"sv, process_manager.serialize_json()); +} + +} diff --git a/Libraries/LibWebView/WebUI/ProcessesUI.h b/Libraries/LibWebView/WebUI/ProcessesUI.h new file mode 100644 index 00000000000..0af21336809 --- /dev/null +++ b/Libraries/LibWebView/WebUI/ProcessesUI.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace WebView { + +class ProcessesUI : public WebUI { + WEB_UI(ProcessesUI); + +private: + virtual void register_interfaces() override; + + void update_process_statistics(); +}; + +} diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 433328b8be9..ce2f2c445cb 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -704,11 +704,6 @@ void PageClient::page_did_mutate_dom(FlyString const& type, Web::DOM::Node const client().async_did_mutate_dom(m_id, { type.to_string(), target.unique_id(), move(serialized_target), mutation.release_value() }); } -void PageClient::update_process_statistics() -{ - client().async_update_process_statistics(m_id); -} - void PageClient::request_current_settings() { client().async_request_current_settings(m_id); diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h index b2cb0db6ce6..9f26a2ffb7b 100644 --- a/Services/WebContent/PageClient.h +++ b/Services/WebContent/PageClient.h @@ -175,7 +175,6 @@ private: virtual IPC::File request_worker_agent() override; virtual void page_did_mutate_dom(FlyString const& type, Web::DOM::Node const& target, Web::DOM::NodeList& added_nodes, Web::DOM::NodeList& removed_nodes, GC::Ptr previous_sibling, GC::Ptr next_sibling, Optional const& attribute_name) override; virtual void received_message_from_web_ui(String const& name, JS::Value data) override; - virtual void update_process_statistics() override; virtual void request_current_settings() override; virtual void restore_default_settings() override; virtual void set_new_tab_page_url(URL::URL const&) override; diff --git a/Services/WebContent/WebContentClient.ipc b/Services/WebContent/WebContentClient.ipc index e1bfacc844c..436240210e2 100644 --- a/Services/WebContent/WebContentClient.ipc +++ b/Services/WebContent/WebContentClient.ipc @@ -109,8 +109,6 @@ endpoint WebContentClient request_worker_agent(u64 page_id) => (IPC::File socket) // FIXME: Add required attributes to select a SharedWorker Agent - update_process_statistics(u64 page_id) =| - request_current_settings(u64 page_id) =| restore_default_settings(u64 page_id) =| set_new_tab_page_url(u64 page_id, URL::URL new_tab_page_url) =|