mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-10-04 00:59:34 +03:00
LibWebView+LibCore: Manage process lifecycle using a SIGCHLD handler
This large commit also refactors LibWebView's process handling to use a top-level Application class that uses a new WebView::Process class to encapsulate the IPC-centric nature of each helper process.
This commit is contained in:
parent
3dea602d92
commit
4cc3d598f9
Notes:
sideshowbarker
2024-07-17 06:51:10 +09:00
Author: https://github.com/ADKaster Commit: https://github.com/LadybirdBrowser/ladybird/commit/4cc3d598f9 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/319
@ -290,6 +290,10 @@
|
|||||||
# cmakedefine01 WEBGL_CONTEXT_DEBUG
|
# cmakedefine01 WEBGL_CONTEXT_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WEBVIEW_PROCESS_DEBUG
|
||||||
|
# cmakedefine01 WEBVIEW_PROCESS_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef WEB_FETCH_DEBUG
|
#ifndef WEB_FETCH_DEBUG
|
||||||
# cmakedefine01 WEB_FETCH_DEBUG
|
# cmakedefine01 WEB_FETCH_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibCore/Timer.h>
|
#include <LibCore/Timer.h>
|
||||||
#include <LibWebView/ProcessManager.h>
|
#include <LibWebView/Application.h>
|
||||||
|
|
||||||
#import <UI/LadybirdWebView.h>
|
#import <UI/LadybirdWebView.h>
|
||||||
#import <UI/TaskManager.h>
|
#import <UI/TaskManager.h>
|
||||||
@ -77,8 +77,8 @@ static constexpr CGFloat const WINDOW_HEIGHT = 400;
|
|||||||
|
|
||||||
- (void)updateStatistics
|
- (void)updateStatistics
|
||||||
{
|
{
|
||||||
WebView::ProcessManager::the().update_all_processes();
|
WebView::Application::the().update_process_statistics();
|
||||||
[self.web_view loadHTML:WebView::ProcessManager::the().generate_html()];
|
[self.web_view loadHTML:WebView::Application::the().generate_process_statistics_html()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -10,13 +10,12 @@
|
|||||||
#include <Ladybird/Types.h>
|
#include <Ladybird/Types.h>
|
||||||
#include <Ladybird/Utilities.h>
|
#include <Ladybird/Utilities.h>
|
||||||
#include <LibCore/ArgsParser.h>
|
#include <LibCore/ArgsParser.h>
|
||||||
#include <LibCore/EventLoop.h>
|
|
||||||
#include <LibGfx/Font/FontDatabase.h>
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
#include <LibMain/Main.h>
|
#include <LibMain/Main.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/ChromeProcess.h>
|
#include <LibWebView/ChromeProcess.h>
|
||||||
#include <LibWebView/CookieJar.h>
|
#include <LibWebView/CookieJar.h>
|
||||||
#include <LibWebView/Database.h>
|
#include <LibWebView/Database.h>
|
||||||
#include <LibWebView/ProcessManager.h>
|
|
||||||
#include <LibWebView/URL.h>
|
#include <LibWebView/URL.h>
|
||||||
#include <LibWebView/ViewImplementation.h>
|
#include <LibWebView/ViewImplementation.h>
|
||||||
#include <LibWebView/WebContentClient.h>
|
#include <LibWebView/WebContentClient.h>
|
||||||
@ -77,7 +76,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
Application* application = [Application sharedApplication];
|
Application* application = [Application sharedApplication];
|
||||||
|
|
||||||
Core::EventLoopManager::install(*new Ladybird::CFEventLoopManager);
|
Core::EventLoopManager::install(*new Ladybird::CFEventLoopManager);
|
||||||
Core::EventLoop event_loop;
|
WebView::Application web_view_app(arguments.argc, arguments.argv);
|
||||||
|
|
||||||
platform_init();
|
platform_init();
|
||||||
|
|
||||||
@ -118,16 +117,14 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
open_urls_from_client(raw_urls, NewWindow::Yes);
|
open_urls_from_client(raw_urls, NewWindow::Yes);
|
||||||
};
|
};
|
||||||
|
|
||||||
WebView::ProcessManager::initialize();
|
|
||||||
|
|
||||||
auto mach_port_server = make<Ladybird::MachPortServer>();
|
auto mach_port_server = make<Ladybird::MachPortServer>();
|
||||||
set_mach_server_name(mach_port_server->server_port_name());
|
set_mach_server_name(mach_port_server->server_port_name());
|
||||||
mach_port_server->on_receive_child_mach_port = [](auto pid, auto port) {
|
mach_port_server->on_receive_child_mach_port = [&web_view_app](auto pid, auto port) {
|
||||||
WebView::ProcessManager::the().add_process(pid, move(port));
|
web_view_app.set_process_mach_port(pid, move(port));
|
||||||
};
|
};
|
||||||
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
||||||
auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id);
|
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
|
||||||
view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
|
view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto database = TRY(WebView::Database::create());
|
auto database = TRY(WebView::Database::create());
|
||||||
@ -158,5 +155,5 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
|
|
||||||
[NSApp setDelegate:delegate];
|
[NSApp setDelegate:delegate];
|
||||||
|
|
||||||
return event_loop.exec();
|
return web_view_app.exec();
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
#include <AK/Enumerate.h>
|
#include <AK/Enumerate.h>
|
||||||
#include <LibCore/Process.h>
|
#include <LibCore/Process.h>
|
||||||
#include <LibWebView/ProcessManager.h>
|
#include <LibWebView/Application.h>
|
||||||
|
|
||||||
template<typename ClientType, typename... ClientArguments>
|
template<typename ClientType, typename... ClientArguments>
|
||||||
static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
||||||
@ -45,7 +45,7 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
|||||||
if constexpr (requires { process.client->set_pid(pid_t {}); })
|
if constexpr (requires { process.client->set_pid(pid_t {}); })
|
||||||
process.client->set_pid(process.process.pid());
|
process.client->set_pid(process.process.pid());
|
||||||
|
|
||||||
WebView::ProcessManager::the().add_process(WebView::process_type_from_name(server_name), process.process.pid());
|
WebView::Application::the().add_child_process(WebView::Process { WebView::process_type_from_name(server_name), process.client, move(process.process) });
|
||||||
|
|
||||||
if (enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) {
|
if (enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) {
|
||||||
dbgln();
|
dbgln();
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TaskManagerWindow.h"
|
#include "TaskManagerWindow.h"
|
||||||
#include <LibWebView/ProcessManager.h>
|
#include <LibWebView/Application.h>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
namespace Ladybird {
|
namespace Ladybird {
|
||||||
@ -41,9 +41,8 @@ void TaskManagerWindow::hideEvent(QHideEvent*)
|
|||||||
|
|
||||||
void TaskManagerWindow::update_statistics()
|
void TaskManagerWindow::update_statistics()
|
||||||
{
|
{
|
||||||
|
WebView::Application::the().update_process_statistics();
|
||||||
WebView::ProcessManager::the().update_all_processes();
|
m_web_view->load_html(WebView::Application::the().generate_process_statistics_html());
|
||||||
m_web_view->load_html(WebView::ProcessManager::the().generate_html());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <LibGfx/Font/FontDatabase.h>
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
#include <LibMain/Main.h>
|
#include <LibMain/Main.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/ChromeProcess.h>
|
#include <LibWebView/ChromeProcess.h>
|
||||||
#include <LibWebView/CookieJar.h>
|
#include <LibWebView/CookieJar.h>
|
||||||
#include <LibWebView/Database.h>
|
#include <LibWebView/Database.h>
|
||||||
@ -76,8 +77,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
Ladybird::Application app(arguments.argc, arguments.argv);
|
Ladybird::Application app(arguments.argc, arguments.argv);
|
||||||
|
|
||||||
Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt);
|
Core::EventLoopManager::install(*new Ladybird::EventLoopManagerQt);
|
||||||
Core::EventLoop event_loop;
|
WebView::Application webview_app(arguments.argc, arguments.argv);
|
||||||
static_cast<Ladybird::EventLoopImplementationQt&>(event_loop.impl()).set_main_loop();
|
static_cast<Ladybird::EventLoopImplementationQt&>(Core::EventLoop::current().impl()).set_main_loop();
|
||||||
|
|
||||||
TRY(handle_attached_debugger());
|
TRY(handle_attached_debugger());
|
||||||
|
|
||||||
@ -142,17 +143,15 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
window.view().load(file_url);
|
window.view().load(file_url);
|
||||||
};
|
};
|
||||||
|
|
||||||
WebView::ProcessManager::initialize();
|
|
||||||
|
|
||||||
#if defined(AK_OS_MACOS)
|
#if defined(AK_OS_MACOS)
|
||||||
auto mach_port_server = make<Ladybird::MachPortServer>();
|
auto mach_port_server = make<Ladybird::MachPortServer>();
|
||||||
set_mach_server_name(mach_port_server->server_port_name());
|
set_mach_server_name(mach_port_server->server_port_name());
|
||||||
mach_port_server->on_receive_child_mach_port = [](auto pid, auto port) {
|
mach_port_server->on_receive_child_mach_port = [&webview_app](auto pid, auto port) {
|
||||||
WebView::ProcessManager::the().add_process(pid, move(port));
|
webview_app.set_process_mach_port(pid, move(port));
|
||||||
};
|
};
|
||||||
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
|
||||||
auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id);
|
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
|
||||||
view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
|
view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -204,5 +203,5 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
|
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
return event_loop.exec();
|
return webview_app.exec();
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ set(WASM_VALIDATOR_DEBUG ON)
|
|||||||
set(WEBDRIVER_DEBUG ON)
|
set(WEBDRIVER_DEBUG ON)
|
||||||
set(WEBDRIVER_ROUTE_DEBUG ON)
|
set(WEBDRIVER_ROUTE_DEBUG ON)
|
||||||
set(WEBGL_CONTEXT_DEBUG ON)
|
set(WEBGL_CONTEXT_DEBUG ON)
|
||||||
|
set(WEBVIEW_PROCESS_DEBUG ON)
|
||||||
set(WEB_FETCH_DEBUG ON)
|
set(WEB_FETCH_DEBUG ON)
|
||||||
set(WEB_WORKER_DEBUG ON)
|
set(WEB_WORKER_DEBUG ON)
|
||||||
set(WEBP_DEBUG ON)
|
set(WEBP_DEBUG ON)
|
||||||
|
@ -31,6 +31,7 @@ class MimeData;
|
|||||||
class NetworkJob;
|
class NetworkJob;
|
||||||
class NetworkResponse;
|
class NetworkResponse;
|
||||||
class Notifier;
|
class Notifier;
|
||||||
|
class Process;
|
||||||
class ProcessStatisticsReader;
|
class ProcessStatisticsReader;
|
||||||
class Resource;
|
class Resource;
|
||||||
class ResourceImplementation;
|
class ResourceImplementation;
|
||||||
|
@ -20,8 +20,6 @@ struct ProcessInfo {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ProcessInfo() = default;
|
|
||||||
|
|
||||||
pid_t pid { 0 };
|
pid_t pid { 0 };
|
||||||
|
|
||||||
u64 memory_usage_bytes { 0 };
|
u64 memory_usage_bytes { 0 };
|
||||||
@ -30,12 +28,6 @@ struct ProcessInfo {
|
|||||||
u64 time_spent_in_process { 0 };
|
u64 time_spent_in_process { 0 };
|
||||||
|
|
||||||
#if defined(AK_OS_MACH)
|
#if defined(AK_OS_MACH)
|
||||||
ProcessInfo(pid_t pid, Core::MachPort&& port)
|
|
||||||
: pid(pid)
|
|
||||||
, child_task_port(move(port))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Core::MachPort child_task_port;
|
Core::MachPort child_task_port;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
namespace Core::Platform {
|
namespace Core::Platform {
|
||||||
|
|
||||||
struct ProcessStatistics {
|
struct ProcessStatistics {
|
||||||
template<typename ProcessInfoType, typename Callback>
|
template<typename Callback>
|
||||||
void for_each_process(Callback&& callback)
|
void for_each_process(Callback&& callback)
|
||||||
{
|
{
|
||||||
for (auto& process : processes)
|
for (auto& process : processes)
|
||||||
callback(verify_cast<ProcessInfoType>(*process));
|
callback(*process);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 total_time_scheduled { 0 };
|
u64 total_time_scheduled { 0 };
|
||||||
|
@ -64,6 +64,13 @@ struct ArgvList {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Process Process::current()
|
||||||
|
{
|
||||||
|
auto p = Process { getpid() };
|
||||||
|
p.m_should_disown = false;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<Process> Process::spawn(ProcessSpawnOptions const& options)
|
ErrorOr<Process> Process::spawn(ProcessSpawnOptions const& options)
|
||||||
{
|
{
|
||||||
#define CHECK(invocation) \
|
#define CHECK(invocation) \
|
||||||
|
@ -74,6 +74,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<Process> spawn(ProcessSpawnOptions const& options);
|
static ErrorOr<Process> spawn(ProcessSpawnOptions const& options);
|
||||||
|
static Process current();
|
||||||
|
|
||||||
// FIXME: Make the following 2 functions return Process instance or delete them.
|
// FIXME: Make the following 2 functions return Process instance or delete them.
|
||||||
static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
||||||
|
@ -20,9 +20,6 @@ void Client::die()
|
|||||||
promise->reject(Error::from_string_literal("ImageDecoder disconnected"));
|
promise->reject(Error::from_string_literal("ImageDecoder disconnected"));
|
||||||
}
|
}
|
||||||
m_pending_decoded_images.clear();
|
m_pending_decoded_images.clear();
|
||||||
|
|
||||||
if (on_death)
|
|
||||||
on_death();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<Core::Promise<DecodedImage>> Client::decode_image(ReadonlyBytes encoded_data, Function<ErrorOr<void>(DecodedImage&)> on_resolved, Function<void(Error&)> on_rejected, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> mime_type)
|
NonnullRefPtr<Core::Promise<DecodedImage>> Client::decode_image(ReadonlyBytes encoded_data, Function<ErrorOr<void>(DecodedImage&)> on_resolved, Function<void(Error&)> on_rejected, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> mime_type)
|
||||||
|
100
Userland/Libraries/LibWebView/Application.cpp
Normal file
100
Userland/Libraries/LibWebView/Application.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Debug.h>
|
||||||
|
#include <LibImageDecoderClient/Client.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
|
#include <LibWebView/WebContentClient.h>
|
||||||
|
|
||||||
|
namespace WebView {
|
||||||
|
|
||||||
|
Application* Application::s_the = nullptr;
|
||||||
|
|
||||||
|
Application::Application(int, char**)
|
||||||
|
{
|
||||||
|
VERIFY(!s_the);
|
||||||
|
s_the = this;
|
||||||
|
|
||||||
|
m_process_manager.on_process_exited = [this](Process&& process) {
|
||||||
|
process_did_exit(move(process));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application()
|
||||||
|
{
|
||||||
|
s_the = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Application::exec()
|
||||||
|
{
|
||||||
|
int ret = m_event_loop.exec();
|
||||||
|
m_in_shutdown = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::add_child_process(WebView::Process&& process)
|
||||||
|
{
|
||||||
|
m_process_manager.add_process(move(process));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACH)
|
||||||
|
void Application::set_process_mach_port(pid_t pid, Core::MachPort&& port)
|
||||||
|
{
|
||||||
|
m_process_manager.set_process_mach_port(pid, move(port));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Optional<Process&> Application::find_process(pid_t pid)
|
||||||
|
{
|
||||||
|
return m_process_manager.find_process(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::update_process_statistics()
|
||||||
|
{
|
||||||
|
m_process_manager.update_all_process_statistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
String Application::generate_process_statistics_html()
|
||||||
|
{
|
||||||
|
return m_process_manager.generate_html();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::process_did_exit(Process&& process)
|
||||||
|
{
|
||||||
|
if (m_in_shutdown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dbgln_if(WEBVIEW_PROCESS_DEBUG, "Process {} died, type: {}", process.pid(), process_name_from_type(process.type()));
|
||||||
|
|
||||||
|
switch (process.type()) {
|
||||||
|
case ProcessType::ImageDecoder:
|
||||||
|
if (auto client = process.client<ImageDecoderClient::Client>(); client.has_value()) {
|
||||||
|
dbgln_if(WEBVIEW_PROCESS_DEBUG, "Restart ImageDecoder process");
|
||||||
|
if (auto on_death = move(client->on_death)) {
|
||||||
|
on_death();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProcessType::RequestServer:
|
||||||
|
dbgln_if(WEBVIEW_PROCESS_DEBUG, "FIXME: Restart request server");
|
||||||
|
break;
|
||||||
|
case ProcessType::WebContent:
|
||||||
|
if (auto client = process.client<WebContentClient>(); client.has_value()) {
|
||||||
|
dbgln_if(WEBVIEW_PROCESS_DEBUG, "Restart WebContent process");
|
||||||
|
if (auto on_web_content_process_crash = move(client->on_web_content_process_crash))
|
||||||
|
on_web_content_process_crash();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProcessType::WebWorker:
|
||||||
|
dbgln_if(WEBVIEW_PROCESS_DEBUG, "WebWorker {} died, not sure what to do.", process.pid());
|
||||||
|
break;
|
||||||
|
case ProcessType::Chrome:
|
||||||
|
dbgln("Invalid process type to be dying: Chrome");
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
51
Userland/Libraries/LibWebView/Application.h
Normal file
51
Userland/Libraries/LibWebView/Application.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibCore/EventLoop.h>
|
||||||
|
#include <LibWebView/Process.h>
|
||||||
|
#include <LibWebView/ProcessManager.h>
|
||||||
|
|
||||||
|
namespace WebView {
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
AK_MAKE_NONCOPYABLE(Application);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Application(int argc, char** argv);
|
||||||
|
virtual ~Application();
|
||||||
|
|
||||||
|
int exec();
|
||||||
|
|
||||||
|
static Application& the() { return *s_the; }
|
||||||
|
|
||||||
|
Core::EventLoop& event_loop() { return m_event_loop; }
|
||||||
|
|
||||||
|
void add_child_process(Process&&);
|
||||||
|
|
||||||
|
// FIXME: Should these methods be part of Application, instead of deferring to ProcessManager?
|
||||||
|
#if defined(AK_OS_MACH)
|
||||||
|
void set_process_mach_port(pid_t, Core::MachPort&&);
|
||||||
|
#endif
|
||||||
|
Optional<Process&> find_process(pid_t);
|
||||||
|
|
||||||
|
// FIXME: Should we just expose the ProcessManager via a getter?
|
||||||
|
void update_process_statistics();
|
||||||
|
String generate_process_statistics_html();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void process_did_exit(Process&&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Application* s_the;
|
||||||
|
|
||||||
|
Core::EventLoop m_event_loop;
|
||||||
|
ProcessManager m_process_manager;
|
||||||
|
bool m_in_shutdown { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,12 +1,14 @@
|
|||||||
include(${SerenityOS_SOURCE_DIR}/Meta/CMake/public_suffix.cmake)
|
include(${SerenityOS_SOURCE_DIR}/Meta/CMake/public_suffix.cmake)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
|
Application.cpp
|
||||||
Attribute.cpp
|
Attribute.cpp
|
||||||
ChromeProcess.cpp
|
ChromeProcess.cpp
|
||||||
CookieJar.cpp
|
CookieJar.cpp
|
||||||
Database.cpp
|
Database.cpp
|
||||||
InspectorClient.cpp
|
InspectorClient.cpp
|
||||||
ProcessHandle.cpp
|
ProcessHandle.cpp
|
||||||
|
Process.cpp
|
||||||
ProcessManager.cpp
|
ProcessManager.cpp
|
||||||
RequestServerAdapter.cpp
|
RequestServerAdapter.cpp
|
||||||
SearchEngine.cpp
|
SearchEngine.cpp
|
||||||
@ -46,7 +48,7 @@ set(GENERATED_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
serenity_lib(LibWebView webview)
|
serenity_lib(LibWebView webview)
|
||||||
target_link_libraries(LibWebView PRIVATE LibCore LibFileSystem LibGfx LibIPC LibProtocol LibJS LibWeb LibUnicode LibURL)
|
target_link_libraries(LibWebView PRIVATE LibCore LibFileSystem LibGfx LibImageDecoderClient LibIPC LibProtocol LibJS LibWeb LibUnicode LibURL)
|
||||||
target_compile_definitions(LibWebView PRIVATE ENABLE_PUBLIC_SUFFIX=$<BOOL:${ENABLE_PUBLIC_SUFFIX_DOWNLOAD}>)
|
target_compile_definitions(LibWebView PRIVATE ENABLE_PUBLIC_SUFFIX=$<BOOL:${ENABLE_PUBLIC_SUFFIX_DOWNLOAD}>)
|
||||||
|
|
||||||
# Third-party
|
# Third-party
|
||||||
|
25
Userland/Libraries/LibWebView/Process.cpp
Normal file
25
Userland/Libraries/LibWebView/Process.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibCore/Process.h>
|
||||||
|
#include <LibWebView/Process.h>
|
||||||
|
|
||||||
|
namespace WebView {
|
||||||
|
|
||||||
|
Process::Process(ProcessType type, RefPtr<IPC::ConnectionBase> connection, Core::Process process)
|
||||||
|
: m_process(move(process))
|
||||||
|
, m_type(type)
|
||||||
|
, m_connection(move(connection))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Process::~Process()
|
||||||
|
{
|
||||||
|
if (m_connection)
|
||||||
|
m_connection->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
46
Userland/Libraries/LibWebView/Process.h
Normal file
46
Userland/Libraries/LibWebView/Process.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <AK/WeakPtr.h>
|
||||||
|
#include <LibCore/Process.h>
|
||||||
|
#include <LibIPC/Connection.h>
|
||||||
|
#include <LibWebView/ProcessType.h>
|
||||||
|
|
||||||
|
namespace WebView {
|
||||||
|
|
||||||
|
class Process {
|
||||||
|
AK_MAKE_NONCOPYABLE(Process);
|
||||||
|
AK_MAKE_DEFAULT_MOVABLE(Process);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Process(ProcessType type, RefPtr<IPC::ConnectionBase> connection, Core::Process process);
|
||||||
|
~Process();
|
||||||
|
|
||||||
|
ProcessType type() const { return m_type; }
|
||||||
|
Optional<String> const& title() const { return m_title; }
|
||||||
|
void set_title(Optional<String> title) { m_title = move(title); }
|
||||||
|
|
||||||
|
template<typename ConnectionFromClient>
|
||||||
|
Optional<ConnectionFromClient&> client()
|
||||||
|
{
|
||||||
|
if (auto strong_connection = m_connection.strong_ref())
|
||||||
|
return verify_cast<ConnectionFromClient>(*strong_connection);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t pid() const { return m_process.pid(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::Process m_process;
|
||||||
|
ProcessType m_type;
|
||||||
|
Optional<String> m_title;
|
||||||
|
WeakPtr<IPC::ConnectionBase> m_connection;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/Optional.h>
|
|
||||||
#include <AK/String.h>
|
|
||||||
#include <AK/Types.h>
|
|
||||||
#include <LibCore/Platform/ProcessInfo.h>
|
|
||||||
|
|
||||||
#if defined(AK_OS_MACH)
|
|
||||||
# include <LibCore/MachPort.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace WebView {
|
|
||||||
|
|
||||||
enum class ProcessType {
|
|
||||||
Chrome,
|
|
||||||
WebContent,
|
|
||||||
WebWorker,
|
|
||||||
RequestServer,
|
|
||||||
ImageDecoder,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProcessInfo : public Core::Platform::ProcessInfo {
|
|
||||||
using Core::Platform::ProcessInfo::ProcessInfo;
|
|
||||||
|
|
||||||
ProcessInfo(ProcessType type, pid_t pid)
|
|
||||||
: Core::Platform::ProcessInfo(pid)
|
|
||||||
, type(type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessType type { ProcessType::WebContent };
|
|
||||||
Optional<String> title;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
namespace WebView {
|
namespace WebView {
|
||||||
|
|
||||||
static sig_atomic_t s_received_sigchld = 0;
|
|
||||||
|
|
||||||
ProcessType process_type_from_name(StringView name)
|
ProcessType process_type_from_name(StringView name)
|
||||||
{
|
{
|
||||||
if (name == "Chrome"sv)
|
if (name == "Chrome"sv)
|
||||||
@ -49,96 +47,74 @@ StringView process_name_from_type(ProcessType type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProcessManager::ProcessManager()
|
ProcessManager::ProcessManager()
|
||||||
|
: on_process_exited([](Process&&) {})
|
||||||
{
|
{
|
||||||
}
|
m_signal_handle = Core::EventLoop::register_signal(SIGCHLD, [this](int) {
|
||||||
|
|
||||||
ProcessManager::~ProcessManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessManager& ProcessManager::the()
|
|
||||||
{
|
|
||||||
static ProcessManager s_the;
|
|
||||||
return s_the;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessManager::initialize()
|
|
||||||
{
|
|
||||||
// FIXME: Should we change this to call EventLoop::register_signal?
|
|
||||||
// Note that only EventLoopImplementationUnix has a working register_signal
|
|
||||||
|
|
||||||
struct sigaction action { };
|
|
||||||
action.sa_flags = SA_RESTART;
|
|
||||||
action.sa_sigaction = [](int, auto*, auto) {
|
|
||||||
s_received_sigchld = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
MUST(Core::System::sigaction(SIGCHLD, &action, nullptr));
|
|
||||||
|
|
||||||
the().add_process(WebView::ProcessType::Chrome, getpid());
|
|
||||||
#ifdef AK_OS_MACH
|
|
||||||
auto self_send_port = mach_task_self();
|
|
||||||
auto res = mach_port_mod_refs(mach_task_self(), self_send_port, MACH_PORT_RIGHT_SEND, +1);
|
|
||||||
VERIFY(res == KERN_SUCCESS);
|
|
||||||
the().add_process(getpid(), Core::MachPort::adopt_right(self_send_port, Core::MachPort::PortRight::Send));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessInfo* ProcessManager::find_process(pid_t pid)
|
|
||||||
{
|
|
||||||
if (auto existing_process = m_statistics.processes.find_if([&](auto& info) { return info->pid == pid; }); !existing_process.is_end())
|
|
||||||
return verify_cast<ProcessInfo>(existing_process->ptr());
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessManager::add_process(ProcessType type, pid_t pid)
|
|
||||||
{
|
|
||||||
Threading::MutexLocker locker { m_lock };
|
|
||||||
if (auto* existing_process = find_process(pid)) {
|
|
||||||
existing_process->type = type;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_statistics.processes.append(make<ProcessInfo>(type, pid));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(AK_OS_MACH)
|
|
||||||
void ProcessManager::add_process(pid_t pid, Core::MachPort&& port)
|
|
||||||
{
|
|
||||||
Threading::MutexLocker locker { m_lock };
|
|
||||||
if (auto* existing_process = find_process(pid)) {
|
|
||||||
existing_process->child_task_port = move(port);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_statistics.processes.append(make<ProcessInfo>(pid, move(port)));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ProcessManager::remove_process(pid_t pid)
|
|
||||||
{
|
|
||||||
Threading::MutexLocker locker { m_lock };
|
|
||||||
m_statistics.processes.remove_first_matching([&](auto const& info) {
|
|
||||||
if (info->pid == pid) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessManager::update_all_processes()
|
|
||||||
{
|
|
||||||
if (s_received_sigchld) {
|
|
||||||
s_received_sigchld = 0;
|
|
||||||
auto result = Core::System::waitpid(-1, WNOHANG);
|
auto result = Core::System::waitpid(-1, WNOHANG);
|
||||||
while (!result.is_error() && result.value().pid > 0) {
|
while (!result.is_error() && result.value().pid > 0) {
|
||||||
auto& [pid, status] = result.value();
|
auto& [pid, status] = result.value();
|
||||||
if (WIFEXITED(status) || WIFSIGNALED(status)) {
|
if (WIFEXITED(status) || WIFSIGNALED(status)) {
|
||||||
remove_process(pid);
|
if (auto process = remove_process(pid); process.has_value())
|
||||||
|
on_process_exited(process.release_value());
|
||||||
}
|
}
|
||||||
result = Core::System::waitpid(-1, WNOHANG);
|
result = Core::System::waitpid(-1, WNOHANG);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
add_process(Process(WebView::ProcessType::Chrome, nullptr, Core::Process::current()));
|
||||||
|
|
||||||
|
#ifdef AK_OS_MACH
|
||||||
|
auto self_send_port = mach_task_self();
|
||||||
|
auto res = mach_port_mod_refs(mach_task_self(), self_send_port, MACH_PORT_RIGHT_SEND, +1);
|
||||||
|
VERIFY(res == KERN_SUCCESS);
|
||||||
|
set_process_mach_port(getpid(), Core::MachPort::adopt_right(self_send_port, Core::MachPort::PortRight::Send));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessManager::~ProcessManager()
|
||||||
|
{
|
||||||
|
Core::EventLoop::unregister_signal(m_signal_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Process&> ProcessManager::find_process(pid_t pid)
|
||||||
|
{
|
||||||
|
return m_processes.get(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessManager::add_process(WebView::Process&& process)
|
||||||
|
{
|
||||||
|
Threading::MutexLocker locker { m_lock };
|
||||||
|
|
||||||
|
auto pid = process.pid();
|
||||||
|
auto result = m_processes.set(pid, move(process));
|
||||||
|
VERIFY(result == AK::HashSetResult::InsertedNewEntry);
|
||||||
|
m_statistics.processes.append(make<Core::Platform::ProcessInfo>(pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACH)
|
||||||
|
void ProcessManager::set_process_mach_port(pid_t pid, Core::MachPort&& port)
|
||||||
|
{
|
||||||
|
Threading::MutexLocker locker { m_lock };
|
||||||
|
for (auto const& info : m_statistics.processes) {
|
||||||
|
if (info->pid == pid) {
|
||||||
|
info->child_task_port = move(port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Optional<Process> ProcessManager::remove_process(pid_t pid)
|
||||||
|
{
|
||||||
|
Threading::MutexLocker locker { m_lock };
|
||||||
|
m_statistics.processes.remove_first_matching([&](auto const& info) {
|
||||||
|
return (info->pid == pid);
|
||||||
|
});
|
||||||
|
return m_processes.take(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessManager::update_all_process_statistics()
|
||||||
|
{
|
||||||
Threading::MutexLocker locker { m_lock };
|
Threading::MutexLocker locker { m_lock };
|
||||||
(void)update_process_statistics(m_statistics);
|
(void)update_process_statistics(m_statistics);
|
||||||
}
|
}
|
||||||
@ -198,12 +174,13 @@ String ProcessManager::generate_html()
|
|||||||
<tbody>
|
<tbody>
|
||||||
)"sv);
|
)"sv);
|
||||||
|
|
||||||
m_statistics.for_each_process<ProcessInfo>([&](auto const& process) {
|
m_statistics.for_each_process([&](auto const& process) {
|
||||||
builder.append("<tr>"sv);
|
builder.append("<tr>"sv);
|
||||||
builder.append("<td>"sv);
|
builder.append("<td>"sv);
|
||||||
builder.append(WebView::process_name_from_type(process.type));
|
auto& process_handle = this->find_process(process.pid).value();
|
||||||
if (process.title.has_value())
|
builder.append(WebView::process_name_from_type(process_handle.type()));
|
||||||
builder.appendff(" - {}", escape_html_entities(*process.title));
|
if (process_handle.title().has_value())
|
||||||
|
builder.appendff(" - {}", escape_html_entities(*process_handle.title()));
|
||||||
builder.append("</td>"sv);
|
builder.append("</td>"sv);
|
||||||
builder.append("<td>"sv);
|
builder.append("<td>"sv);
|
||||||
builder.append(MUST(String::number(process.pid)));
|
builder.append(MUST(String::number(process.pid)));
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
#include <LibCore/Platform/ProcessStatistics.h>
|
#include <LibCore/Platform/ProcessStatistics.h>
|
||||||
#include <LibThreading/Mutex.h>
|
#include <LibThreading/Mutex.h>
|
||||||
#include <LibWebView/Forward.h>
|
#include <LibWebView/Forward.h>
|
||||||
#include <LibWebView/ProcessInfo.h>
|
#include <LibWebView/Process.h>
|
||||||
|
#include <LibWebView/ProcessType.h>
|
||||||
|
|
||||||
namespace WebView {
|
namespace WebView {
|
||||||
|
|
||||||
@ -20,26 +21,29 @@ ProcessType process_type_from_name(StringView);
|
|||||||
StringView process_name_from_type(ProcessType type);
|
StringView process_name_from_type(ProcessType type);
|
||||||
|
|
||||||
class ProcessManager {
|
class ProcessManager {
|
||||||
|
AK_MAKE_NONCOPYABLE(ProcessManager);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ProcessManager& the();
|
|
||||||
static void initialize();
|
|
||||||
|
|
||||||
void add_process(WebView::ProcessType, pid_t);
|
|
||||||
void remove_process(pid_t);
|
|
||||||
ProcessInfo* find_process(pid_t);
|
|
||||||
|
|
||||||
#if defined(AK_OS_MACH)
|
|
||||||
void add_process(pid_t, Core::MachPort&&);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void update_all_processes();
|
|
||||||
String generate_html();
|
|
||||||
|
|
||||||
private:
|
|
||||||
ProcessManager();
|
ProcessManager();
|
||||||
~ProcessManager();
|
~ProcessManager();
|
||||||
|
|
||||||
|
void add_process(Process&&);
|
||||||
|
Optional<Process> remove_process(pid_t);
|
||||||
|
Optional<Process&> find_process(pid_t);
|
||||||
|
|
||||||
|
#if defined(AK_OS_MACH)
|
||||||
|
void set_process_mach_port(pid_t, Core::MachPort&&);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void update_all_process_statistics();
|
||||||
|
String generate_html();
|
||||||
|
|
||||||
|
Function<void(Process&&)> on_process_exited;
|
||||||
|
|
||||||
|
private:
|
||||||
Core::Platform::ProcessStatistics m_statistics;
|
Core::Platform::ProcessStatistics m_statistics;
|
||||||
|
HashMap<pid_t, Process> m_processes;
|
||||||
|
int m_signal_handle { -1 };
|
||||||
Threading::Mutex m_lock;
|
Threading::Mutex m_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
21
Userland/Libraries/LibWebView/ProcessType.h
Normal file
21
Userland/Libraries/LibWebView/ProcessType.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Types.h>
|
||||||
|
|
||||||
|
namespace WebView {
|
||||||
|
|
||||||
|
enum class ProcessType : u8 {
|
||||||
|
Chrome,
|
||||||
|
WebContent,
|
||||||
|
WebWorker,
|
||||||
|
RequestServer,
|
||||||
|
ImageDecoder,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "WebContentClient.h"
|
#include "WebContentClient.h"
|
||||||
#include "ProcessManager.h"
|
#include "Application.h"
|
||||||
#include "ViewImplementation.h"
|
#include "ViewImplementation.h"
|
||||||
#include <LibWeb/Cookie/ParsedCookie.h>
|
#include <LibWeb/Cookie/ParsedCookie.h>
|
||||||
|
|
||||||
@ -36,8 +36,7 @@ WebContentClient::~WebContentClient()
|
|||||||
|
|
||||||
void WebContentClient::die()
|
void WebContentClient::die()
|
||||||
{
|
{
|
||||||
VERIFY(on_web_content_process_crash);
|
// Intentionally empty. Restart is handled at another level.
|
||||||
on_web_content_process_crash();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentClient::register_view(u64 page_id, ViewImplementation& view)
|
void WebContentClient::register_view(u64 page_id, ViewImplementation& view)
|
||||||
@ -49,6 +48,9 @@ void WebContentClient::register_view(u64 page_id, ViewImplementation& view)
|
|||||||
void WebContentClient::unregister_view(u64 page_id)
|
void WebContentClient::unregister_view(u64 page_id)
|
||||||
{
|
{
|
||||||
m_views.remove(page_id);
|
m_views.remove(page_id);
|
||||||
|
if (m_views.is_empty()) {
|
||||||
|
on_web_content_process_crash = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContentClient::did_paint(u64 page_id, Gfx::IntRect const& rect, i32 bitmap_id)
|
void WebContentClient::did_paint(u64 page_id, Gfx::IntRect const& rect, i32 bitmap_id)
|
||||||
@ -59,8 +61,8 @@ void WebContentClient::did_paint(u64 page_id, Gfx::IntRect const& rect, i32 bitm
|
|||||||
|
|
||||||
void WebContentClient::did_start_loading(u64 page_id, URL::URL const& url, bool is_redirect)
|
void WebContentClient::did_start_loading(u64 page_id, URL::URL const& url, bool is_redirect)
|
||||||
{
|
{
|
||||||
if (auto* process = WebView::ProcessManager::the().find_process(m_process_handle.pid))
|
if (auto process = WebView::Application::the().find_process(m_process_handle.pid); process.has_value())
|
||||||
process->title.clear();
|
process->set_title(OptionalNone {});
|
||||||
|
|
||||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||||
view->set_url({}, url);
|
view->set_url({}, url);
|
||||||
@ -143,8 +145,8 @@ void WebContentClient::did_layout(u64 page_id, Gfx::IntSize content_size)
|
|||||||
|
|
||||||
void WebContentClient::did_change_title(u64 page_id, ByteString const& title)
|
void WebContentClient::did_change_title(u64 page_id, ByteString const& title)
|
||||||
{
|
{
|
||||||
if (auto* process = WebView::ProcessManager::the().find_process(m_process_handle.pid))
|
if (auto process = WebView::Application::the().find_process(m_process_handle.pid); process.has_value())
|
||||||
process->title = MUST(String::from_byte_string(title));
|
process->set_title(MUST(String::from_byte_string(title)));
|
||||||
|
|
||||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||||
if (!view->on_title_change)
|
if (!view->on_title_change)
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <LibWeb/HTML/ActivateTab.h>
|
#include <LibWeb/HTML/ActivateTab.h>
|
||||||
#include <LibWeb/HTML/SelectedFile.h>
|
#include <LibWeb/HTML/SelectedFile.h>
|
||||||
#include <LibWeb/Worker/WebWorkerClient.h>
|
#include <LibWeb/Worker/WebWorkerClient.h>
|
||||||
|
#include <LibWebView/Application.h>
|
||||||
#include <LibWebView/CookieJar.h>
|
#include <LibWebView/CookieJar.h>
|
||||||
#include <LibWebView/Database.h>
|
#include <LibWebView/Database.h>
|
||||||
#include <LibWebView/URL.h>
|
#include <LibWebView/URL.h>
|
||||||
@ -631,7 +632,7 @@ static ErrorOr<int> run_tests(HeadlessWebContentView& view, StringView test_root
|
|||||||
|
|
||||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
{
|
{
|
||||||
Core::EventLoop event_loop;
|
WebView::Application app(arguments.argc, arguments.argv);
|
||||||
|
|
||||||
int screenshot_timeout = 1;
|
int screenshot_timeout = 1;
|
||||||
StringView raw_url;
|
StringView raw_url;
|
||||||
@ -704,8 +705,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (web_driver_ipc_path.is_empty()) {
|
if (web_driver_ipc_path.is_empty()) {
|
||||||
auto timer = TRY(load_page_for_screenshot_and_exit(event_loop, *view, url.value(), screenshot_timeout));
|
auto timer = TRY(load_page_for_screenshot_and_exit(Core::EventLoop::current(), *view, url.value(), screenshot_timeout));
|
||||||
return event_loop.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user