1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:47:36 +00:00

FileSystemAccessServer+TextEditor: Implement cross-process modal prompts

This transitions from synchronous IPC calls to asynchronous IPC calls
provided through a synchronous interface in LibFileSystemAccessClient
which allows the parent Application to stay responsive.

It achieves this with Promise which is pumping the Application event
loop while waiting for the Dialog to respond with the user's action.

LibFileSystemAccessClient provides a lazy singleton which also ensures
that FileSystemAccessServer is running in the event of a crash.

This also transitions TextEditor into using LibFileSystemAccessClient.
This commit is contained in:
Timothy 2021-07-12 01:16:26 +10:00 committed by Andreas Kling
parent ab353fd4e1
commit 38594dde79
12 changed files with 224 additions and 88 deletions

View file

@ -44,7 +44,6 @@
namespace TextEditor {
MainWidget::MainWidget()
: m_file_system_access_client(FileSystemAccessClient::construct())
{
load_from_gml(text_editor_window_gml);
@ -260,11 +259,11 @@ MainWidget::MainWidget()
});
m_open_action = GUI::CommonActions::make_open_action([this](auto&) {
auto fd_response = m_file_system_access_client->prompt_open_file(Core::StandardPaths::home_directory(), Core::OpenMode::ReadOnly);
auto response = FileSystemAccessClient::Client::the().open_file(window()->window_id());
if (fd_response.error() != 0) {
if (fd_response.error() != -1)
GUI::MessageBox::show_error(window(), String::formatted("Opening \"{}\" failed: {}", fd_response.chosen_file().value(), strerror(fd_response.error())));
if (response.error != 0) {
if (response.error != -1)
GUI::MessageBox::show_error(window(), String::formatted("Opening \"{}\" failed: {}", *response.chosen_file, strerror(response.error)));
return;
}
@ -276,40 +275,40 @@ MainWidget::MainWidget()
return;
}
read_file_and_close(fd_response.fd()->take_fd(), fd_response.chosen_file().value());
read_file_and_close(*response.fd, *response.chosen_file);
});
m_save_as_action = GUI::CommonActions::make_save_as_action([&](auto&) {
auto response = m_file_system_access_client->prompt_save_file(m_name.is_null() ? "Untitled" : m_name, m_extension.is_null() ? "txt" : m_extension, Core::StandardPaths::home_directory(), Core::OpenMode::Truncate | Core::OpenMode::WriteOnly);
auto response = FileSystemAccessClient::Client::the().save_file(window()->window_id(), m_name, m_extension);
if (response.error() != 0) {
if (response.error() != -1)
GUI::MessageBox::show_error(window(), String::formatted("Saving \"{}\" failed: {}", response.chosen_file().value(), strerror(response.error())));
if (response.error != 0) {
if (response.error != -1)
GUI::MessageBox::show_error(window(), String::formatted("Saving \"{}\" failed: {}", *response.chosen_file, strerror(response.error)));
return;
}
if (!m_editor->write_to_file_and_close(response.fd()->take_fd())) {
if (!m_editor->write_to_file_and_close(*response.fd)) {
GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error);
return;
}
// FIXME: It would be cool if this would propagate from GUI::TextDocument somehow.
window()->set_modified(false);
set_path(response.chosen_file().value());
dbgln("Wrote document to {}", response.chosen_file().value());
set_path(*response.chosen_file);
dbgln("Wrote document to {}", *response.chosen_file);
});
m_save_action = GUI::CommonActions::make_save_action([&](auto&) {
if (!m_path.is_empty()) {
auto response = m_file_system_access_client->request_file(m_path, Core::OpenMode::Truncate | Core::OpenMode::WriteOnly);
auto response = FileSystemAccessClient::Client::the().request_file(window()->window_id(), m_path, Core::OpenMode::Truncate | Core::OpenMode::WriteOnly);
if (response.error() != 0) {
if (response.error() != -1)
GUI::MessageBox::show_error(window(), String::formatted("Unable to save file: {}", strerror(response.error())));
if (response.error != 0) {
if (response.error != -1)
GUI::MessageBox::show_error(window(), String::formatted("Unable to save file: {}", strerror(response.error)));
return;
}
int fd = response.fd()->take_fd();
int fd = *response.fd;
if (!m_editor->write_to_file_and_close(fd)) {
GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error);
@ -726,12 +725,14 @@ void MainWidget::drop_event(GUI::DropEvent& event)
GUI::MessageBox::show(window(), "TextEditor can only open one file at a time!", "One at a time please!", GUI::MessageBox::Type::Error);
return;
}
auto file_response = m_file_system_access_client->request_file(urls.first().path(), Core::OpenMode::ReadOnly);
if (file_response.error() != 0)
// TODO: A drop event should be considered user consent for opening a file
auto file_response = FileSystemAccessClient::Client::the().request_file(window()->window_id(), urls.first().path(), Core::OpenMode::ReadOnly);
if (file_response.error != 0)
return;
read_file_and_close(file_response.fd()->take_fd(), urls.first().path());
read_file_and_close(*file_response.fd, urls.first().path());
}
}