1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 02:17:35 +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

@ -0,0 +1,12 @@
set(SOURCES
Client.cpp
)
set(GENERATED_SOURCES
../../Services/FileSystemAccessServer/FileSystemAccessClientEndpoint.h
../../Services/FileSystemAccessServer/FileSystemAccessServerEndpoint.h
)
serenity_lib(LibFileSystemAccessClient filesystemaccessclient)
target_link_libraries(LibFileSystemAccessClient LibIPC)
add_dependencies(LibFileSystemAccessClient WindowServer)

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2021, timmot <tiwwot@protonmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
// FIXME: LibIPC Decoder and Encoder are sensitive to include order here
// clang-format off
#include <LibGUI/WindowServerConnection.h>
// clang-format on
#include <LibCore/StandardPaths.h>
#include <LibFileSystemAccessClient/Client.h>
#include <LibGUI/Window.h>
namespace FileSystemAccessClient {
static RefPtr<Client> s_the = nullptr;
Client& Client::the()
{
if (!s_the || !s_the->is_open())
s_the = Client::construct();
return *s_the;
}
Result Client::request_file(i32 parent_window_id, String const& path, Core::OpenMode mode)
{
m_promise = Core::Promise<Result>::construct();
auto window_server_client_id = GUI::WindowServerConnection::the().expose_client_id();
async_request_file(window_server_client_id, parent_window_id, path, mode);
return m_promise->await();
}
Result Client::open_file(i32 parent_window_id)
{
m_promise = Core::Promise<Result>::construct();
auto window_server_client_id = GUI::WindowServerConnection::the().expose_client_id();
async_prompt_open_file(window_server_client_id, parent_window_id, Core::StandardPaths::home_directory(), Core::OpenMode::ReadOnly);
return m_promise->await();
}
Result Client::save_file(i32 parent_window_id, String const& name, String const ext)
{
m_promise = Core::Promise<Result>::construct();
auto window_server_client_id = GUI::WindowServerConnection::the().expose_client_id();
async_prompt_save_file(window_server_client_id, parent_window_id, name.is_null() ? "Untitled" : name, ext.is_null() ? "txt" : ext, Core::StandardPaths::home_directory(), Core::OpenMode::Truncate | Core::OpenMode::WriteOnly);
return m_promise->await();
}
void Client::handle_prompt_end(i32 error, Optional<IPC::File> const& fd, Optional<String> const& chosen_file)
{
VERIFY(m_promise);
if (error == 0) {
m_promise->resolve({ error, fd->take_fd(), *chosen_file });
} else {
m_promise->resolve({ error, {}, chosen_file });
}
}
void Client::die()
{
if (m_promise)
handle_prompt_end(ECONNRESET, {}, "");
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2021, timmot <tiwwot@protonmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <FileSystemAccessServer/FileSystemAccessClientEndpoint.h>
#include <FileSystemAccessServer/FileSystemAccessServerEndpoint.h>
#include <LibCore/File.h>
#include <LibCore/Promise.h>
#include <LibIPC/ServerConnection.h>
namespace FileSystemAccessClient {
struct Result {
i32 error;
Optional<i32> fd;
Optional<String> chosen_file;
};
class Client final
: public IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>
, public FileSystemAccessClientEndpoint {
C_OBJECT(Client)
public:
Result request_file(i32 parent_window_id, String const& path, Core::OpenMode mode);
Result open_file(i32 parent_window_id);
Result save_file(i32 parent_window_id, String const& name, String const ext);
static Client& the();
protected:
void die() override;
private:
explicit Client()
: IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>(*this, "/tmp/portal/filesystemaccess")
{
}
virtual void handle_prompt_end(i32 error, Optional<IPC::File> const& fd, Optional<String> const& chosen_file) override;
RefPtr<Core::Promise<Result>> m_promise;
};
}