1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 04:27:40 +00:00

LibWebView+WebContent: Wait for dialog responses without blocking IPC

Currently, the WebContent process is completely blocked while waiting
for a response to a dialog request. This patch allows the IPC event loop
to continue executing while only blocking the HTML event loop.

This will allow other processes like WebDriver to continue to operate on
the WebContent process while a dialog is open.
This commit is contained in:
Timothy Flynn 2022-11-15 15:49:36 -05:00 committed by Linus Groh
parent 4b8729aea6
commit 364f44d7d8
11 changed files with 118 additions and 32 deletions

View file

@ -348,20 +348,22 @@ void OutOfProcessWebView::notify_server_did_request_image_context_menu(Badge<Web
void OutOfProcessWebView::notify_server_did_request_alert(Badge<WebContentClient>, String const& message) void OutOfProcessWebView::notify_server_did_request_alert(Badge<WebContentClient>, String const& message)
{ {
GUI::MessageBox::show(window(), message, "Alert"sv, GUI::MessageBox::Type::Information); GUI::MessageBox::show(window(), message, "Alert"sv, GUI::MessageBox::Type::Information);
client().async_alert_closed();
} }
bool OutOfProcessWebView::notify_server_did_request_confirm(Badge<WebContentClient>, String const& message) void OutOfProcessWebView::notify_server_did_request_confirm(Badge<WebContentClient>, String const& message)
{ {
auto confirm_result = GUI::MessageBox::show(window(), message, "Confirm"sv, GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OKCancel); auto confirm_result = GUI::MessageBox::show(window(), message, "Confirm"sv, GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OKCancel);
return confirm_result == GUI::Dialog::ExecResult::OK; client().async_confirm_closed(confirm_result == GUI::Dialog::ExecResult::OK);
} }
String OutOfProcessWebView::notify_server_did_request_prompt(Badge<WebContentClient>, String const& message, String const& default_) void OutOfProcessWebView::notify_server_did_request_prompt(Badge<WebContentClient>, String const& message, String const& default_)
{ {
String response { default_ }; String response { default_ };
if (GUI::InputBox::show(window(), response, message, "Prompt"sv) == GUI::InputBox::ExecResult::OK) if (GUI::InputBox::show(window(), response, message, "Prompt"sv) == GUI::InputBox::ExecResult::OK)
return response; client().async_prompt_closed(move(response));
return {}; else
client().async_prompt_closed({});
} }
void OutOfProcessWebView::notify_server_did_get_source(const AK::URL& url, String const& source) void OutOfProcessWebView::notify_server_did_get_source(const AK::URL& url, String const& source)

View file

@ -156,8 +156,8 @@ private:
virtual void notify_server_did_request_link_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers) override; virtual void notify_server_did_request_link_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers) override;
virtual void notify_server_did_request_image_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers, Gfx::ShareableBitmap const&) override; virtual void notify_server_did_request_image_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers, Gfx::ShareableBitmap const&) override;
virtual void notify_server_did_request_alert(Badge<WebContentClient>, String const& message) override; virtual void notify_server_did_request_alert(Badge<WebContentClient>, String const& message) override;
virtual bool notify_server_did_request_confirm(Badge<WebContentClient>, String const& message) override; virtual void notify_server_did_request_confirm(Badge<WebContentClient>, String const& message) override;
virtual String notify_server_did_request_prompt(Badge<WebContentClient>, String const& message, String const& default_) override; virtual void notify_server_did_request_prompt(Badge<WebContentClient>, String const& message, String const& default_) override;
virtual void notify_server_did_get_source(const AK::URL& url, String const& source) override; virtual void notify_server_did_get_source(const AK::URL& url, String const& source) override;
virtual void notify_server_did_get_dom_tree(String const& dom_tree) override; virtual void notify_server_did_get_dom_tree(String const& dom_tree) override;
virtual void notify_server_did_get_dom_node_properties(i32 node_id, String const& specified_style, String const& computed_style, String const& custom_properties, String const& node_box_sizing) override; virtual void notify_server_did_get_dom_node_properties(i32 node_id, String const& specified_style, String const& computed_style, String const& custom_properties, String const& node_box_sizing) override;

View file

@ -42,8 +42,8 @@ public:
virtual void notify_server_did_request_link_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers) = 0; virtual void notify_server_did_request_link_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers) = 0;
virtual void notify_server_did_request_image_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers, Gfx::ShareableBitmap const&) = 0; virtual void notify_server_did_request_image_context_menu(Badge<WebContentClient>, Gfx::IntPoint const&, const AK::URL&, String const& target, unsigned modifiers, Gfx::ShareableBitmap const&) = 0;
virtual void notify_server_did_request_alert(Badge<WebContentClient>, String const& message) = 0; virtual void notify_server_did_request_alert(Badge<WebContentClient>, String const& message) = 0;
virtual bool notify_server_did_request_confirm(Badge<WebContentClient>, String const& message) = 0; virtual void notify_server_did_request_confirm(Badge<WebContentClient>, String const& message) = 0;
virtual String notify_server_did_request_prompt(Badge<WebContentClient>, String const& message, String const& default_) = 0; virtual void notify_server_did_request_prompt(Badge<WebContentClient>, String const& message, String const& default_) = 0;
virtual void notify_server_did_get_source(const AK::URL& url, String const& source) = 0; virtual void notify_server_did_get_source(const AK::URL& url, String const& source) = 0;
virtual void notify_server_did_get_dom_tree(String const& dom_tree) = 0; virtual void notify_server_did_get_dom_tree(String const& dom_tree) = 0;
virtual void notify_server_did_get_dom_node_properties(i32 node_id, String const& specified_style, String const& computed_style, String const& custom_properties, String const& node_box_sizing) = 0; virtual void notify_server_did_get_dom_node_properties(i32 node_id, String const& specified_style, String const& computed_style, String const& custom_properties, String const& node_box_sizing) = 0;

View file

@ -181,14 +181,14 @@ void WebContentClient::did_request_alert(String const& message)
m_view.notify_server_did_request_alert({}, message); m_view.notify_server_did_request_alert({}, message);
} }
Messages::WebContentClient::DidRequestConfirmResponse WebContentClient::did_request_confirm(String const& message) void WebContentClient::did_request_confirm(String const& message)
{ {
return m_view.notify_server_did_request_confirm({}, message); m_view.notify_server_did_request_confirm({}, message);
} }
Messages::WebContentClient::DidRequestPromptResponse WebContentClient::did_request_prompt(String const& message, String const& default_) void WebContentClient::did_request_prompt(String const& message, String const& default_)
{ {
return m_view.notify_server_did_request_prompt({}, message, default_); m_view.notify_server_did_request_prompt({}, message, default_);
} }
void WebContentClient::did_change_favicon(Gfx::ShareableBitmap const& favicon) void WebContentClient::did_change_favicon(Gfx::ShareableBitmap const& favicon)

View file

@ -58,8 +58,8 @@ private:
virtual void did_get_js_console_messages(i32 start_index, Vector<String> const& message_types, Vector<String> const& messages) override; virtual void did_get_js_console_messages(i32 start_index, Vector<String> const& message_types, Vector<String> const& messages) override;
virtual void did_change_favicon(Gfx::ShareableBitmap const&) override; virtual void did_change_favicon(Gfx::ShareableBitmap const&) override;
virtual void did_request_alert(String const&) override; virtual void did_request_alert(String const&) override;
virtual Messages::WebContentClient::DidRequestConfirmResponse did_request_confirm(String const&) override; virtual void did_request_confirm(String const&) override;
virtual Messages::WebContentClient::DidRequestPromptResponse did_request_prompt(String const&, String const&) override; virtual void did_request_prompt(String const&, String const&) override;
virtual Messages::WebContentClient::DidRequestAllCookiesResponse did_request_all_cookies(AK::URL const&) override; virtual Messages::WebContentClient::DidRequestAllCookiesResponse did_request_all_cookies(AK::URL const&) override;
virtual Messages::WebContentClient::DidRequestNamedCookieResponse did_request_named_cookie(AK::URL const&, String const&) override; virtual Messages::WebContentClient::DidRequestNamedCookieResponse did_request_named_cookie(AK::URL const&, String const&) override;
virtual Messages::WebContentClient::DidRequestCookieResponse did_request_cookie(AK::URL const&, u8) override; virtual Messages::WebContentClient::DidRequestCookieResponse did_request_cookie(AK::URL const&, u8) override;

View file

@ -576,4 +576,19 @@ void ConnectionFromClient::set_system_visibility_state(bool visible)
: Web::HTML::VisibilityState::Hidden); : Web::HTML::VisibilityState::Hidden);
} }
void ConnectionFromClient::alert_closed()
{
m_page_host->alert_closed();
}
void ConnectionFromClient::confirm_closed(bool accepted)
{
m_page_host->confirm_closed(accepted);
}
void ConnectionFromClient::prompt_closed(String const& response)
{
m_page_host->prompt_closed(response);
}
} }

View file

@ -84,6 +84,10 @@ private:
virtual void run_javascript(String const&) override; virtual void run_javascript(String const&) override;
virtual void js_console_request_messages(i32) override; virtual void js_console_request_messages(i32) override;
virtual void alert_closed() override;
virtual void confirm_closed(bool accepted) override;
virtual void prompt_closed(String const& response) override;
virtual Messages::WebContentServer::TakeDocumentScreenshotResponse take_document_screenshot() override; virtual Messages::WebContentServer::TakeDocumentScreenshotResponse take_document_screenshot() override;
virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override; virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override;

View file

@ -7,13 +7,17 @@
#include "PageHost.h" #include "PageHost.h"
#include "ConnectionFromClient.h" #include "ConnectionFromClient.h"
#include <AK/SourceLocation.h>
#include <LibGfx/Painter.h> #include <LibGfx/Painter.h>
#include <LibGfx/ShareableBitmap.h> #include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SystemTheme.h> #include <LibGfx/SystemTheme.h>
#include <LibWeb/Cookie/ParsedCookie.h> #include <LibWeb/Cookie/ParsedCookie.h>
#include <LibWeb/HTML/BrowsingContext.h> #include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/Layout/InitialContainingBlock.h> #include <LibWeb/Layout/InitialContainingBlock.h>
#include <LibWeb/Painting/PaintableBox.h> #include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/Platform/Timer.h> #include <LibWeb/Platform/Timer.h>
#include <WebContent/WebContentClientEndpoint.h> #include <WebContent/WebContentClientEndpoint.h>
#include <WebContent/WebDriverConnection.h> #include <WebContent/WebDriverConnection.h>
@ -233,33 +237,72 @@ void PageHost::page_did_request_link_context_menu(Gfx::IntPoint const& content_p
m_client.async_did_request_link_context_menu(content_position, url, target, modifiers); m_client.async_did_request_link_context_menu(content_position, url, target, modifiers);
} }
template<typename ResponseType>
static ResponseType spin_event_loop_until_dialog_closed(ConnectionFromClient& client, Optional<ResponseType>& response, SourceLocation location = SourceLocation::current())
{
auto& event_loop = Web::HTML::current_settings_object().responsible_event_loop();
ScopeGuard guard { [&] { event_loop.set_execution_paused(false); } };
event_loop.set_execution_paused(true);
Web::Platform::EventLoopPlugin::the().spin_until([&]() {
return response.has_value() || !client.is_open();
});
if (!client.is_open()) {
dbgln("WebContent client disconnected during {}. Exiting peacefully.", location.function_name());
exit(0);
}
return response.release_value();
}
void PageHost::page_did_request_alert(String const& message) void PageHost::page_did_request_alert(String const& message)
{ {
auto response = m_client.send_sync_but_allow_failure<Messages::WebContentClient::DidRequestAlert>(message); m_pending_dialog = PendingDialog::Alert;
if (!response) { m_client.async_did_request_alert(message);
dbgln("WebContent client disconnected during DidRequestAlert. Exiting peacefully.");
exit(0); spin_event_loop_until_dialog_closed(m_client, m_pending_alert_response);
}
void PageHost::alert_closed()
{
if (m_pending_dialog == PendingDialog::Alert) {
m_pending_dialog = PendingDialog::None;
m_pending_alert_response = Empty {};
} }
} }
bool PageHost::page_did_request_confirm(String const& message) bool PageHost::page_did_request_confirm(String const& message)
{ {
auto response = m_client.send_sync_but_allow_failure<Messages::WebContentClient::DidRequestConfirm>(message); m_pending_dialog = PendingDialog::Confirm;
if (!response) { m_client.async_did_request_confirm(message);
dbgln("WebContent client disconnected during DidRequestConfirm. Exiting peacefully.");
exit(0); return spin_event_loop_until_dialog_closed(m_client, m_pending_confirm_response);
}
void PageHost::confirm_closed(bool accepted)
{
if (m_pending_dialog == PendingDialog::Confirm) {
m_pending_dialog = PendingDialog::None;
m_pending_confirm_response = accepted;
} }
return response->take_result();
} }
String PageHost::page_did_request_prompt(String const& message, String const& default_) String PageHost::page_did_request_prompt(String const& message, String const& default_)
{ {
auto response = m_client.send_sync_but_allow_failure<Messages::WebContentClient::DidRequestPrompt>(message, default_); m_pending_dialog = PendingDialog::Prompt;
if (!response) { m_client.async_did_request_prompt(message, default_);
dbgln("WebContent client disconnected during DidRequestPrompt. Exiting peacefully.");
exit(0); return spin_event_loop_until_dialog_closed(m_client, m_pending_prompt_response);
}
void PageHost::prompt_closed(String response)
{
if (m_pending_dialog == PendingDialog::Prompt) {
m_pending_dialog = PendingDialog::None;
m_pending_prompt_response = move(response);
} }
return response->take_response();
} }
void PageHost::page_did_change_favicon(Gfx::Bitmap const& favicon) void PageHost::page_did_change_favicon(Gfx::Bitmap const& favicon)

View file

@ -43,6 +43,19 @@ public:
ErrorOr<void> connect_to_webdriver(String const& webdriver_ipc_path); ErrorOr<void> connect_to_webdriver(String const& webdriver_ipc_path);
void alert_closed();
void confirm_closed(bool accepted);
void prompt_closed(String response);
enum class PendingDialog {
None,
Alert,
Confirm,
Prompt,
};
bool has_pending_dialog() const { return m_pending_dialog != PendingDialog::None; }
PendingDialog pending_dialog() const { return m_pending_dialog; }
private: private:
// ^PageClient // ^PageClient
virtual Gfx::Palette palette() const override; virtual Gfx::Palette palette() const override;
@ -95,6 +108,11 @@ private:
Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto }; Web::CSS::PreferredColorScheme m_preferred_color_scheme { Web::CSS::PreferredColorScheme::Auto };
RefPtr<WebDriverConnection> m_webdriver; RefPtr<WebDriverConnection> m_webdriver;
PendingDialog m_pending_dialog { PendingDialog::None };
Optional<Empty> m_pending_alert_response;
Optional<bool> m_pending_confirm_response;
Optional<String> m_pending_prompt_response;
}; };
} }

View file

@ -29,9 +29,9 @@ endpoint WebContentClient
did_request_context_menu(Gfx::IntPoint content_position) =| did_request_context_menu(Gfx::IntPoint content_position) =|
did_request_link_context_menu(Gfx::IntPoint content_position, URL url, String target, unsigned modifiers) =| did_request_link_context_menu(Gfx::IntPoint content_position, URL url, String target, unsigned modifiers) =|
did_request_image_context_menu(Gfx::IntPoint content_position, URL url, String target, unsigned modifiers, Gfx::ShareableBitmap bitmap) =| did_request_image_context_menu(Gfx::IntPoint content_position, URL url, String target, unsigned modifiers, Gfx::ShareableBitmap bitmap) =|
did_request_alert(String message) => () did_request_alert(String message) =|
did_request_confirm(String message) => (bool result) did_request_confirm(String message) =|
did_request_prompt(String message, String default_) => (String response) did_request_prompt(String message, String default_) =|
did_get_source(URL url, String source) =| did_get_source(URL url, String source) =|
did_get_dom_tree(String dom_tree) =| did_get_dom_tree(String dom_tree) =|
did_get_dom_node_properties(i32 node_id, String specified_style, String computed_style, String custom_properties, String node_box_sizing_json) =| did_get_dom_node_properties(i32 node_id, String specified_style, String computed_style, String custom_properties, String node_box_sizing_json) =|

View file

@ -65,4 +65,8 @@ endpoint WebContentServer
handle_file_return(i32 error, Optional<IPC::File> file, i32 request_id) =| handle_file_return(i32 error, Optional<IPC::File> file, i32 request_id) =|
set_system_visibility_state(bool visible) =| set_system_visibility_state(bool visible) =|
alert_closed() =|
confirm_closed(bool accepted) =|
prompt_closed(String response) =|
} }