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:
parent
ab353fd4e1
commit
38594dde79
Notes:
sideshowbarker
2024-07-18 08:49:45 +09:00
Author: https://github.com/timmot Commit: https://github.com/SerenityOS/serenity/commit/38594dde790 Pull-request: https://github.com/SerenityOS/serenity/pull/8636 Issue: https://github.com/SerenityOS/serenity/issues/8628 Issue: https://github.com/SerenityOS/serenity/issues/8630 Reviewed-by: https://github.com/alimpfard Reviewed-by: https://github.com/awesomekling
12 changed files with 224 additions and 88 deletions
|
@ -15,4 +15,4 @@ set(SOURCES
|
|||
)
|
||||
|
||||
serenity_app(TextEditor ICON app-text-editor)
|
||||
target_link_libraries(TextEditor LibWeb LibMarkdown LibGUI LibShell LibRegex LibDesktop LibCpp LibJS LibSQL)
|
||||
target_link_libraries(TextEditor LibWeb LibMarkdown LibGUI LibShell LibRegex LibDesktop LibCpp LibJS LibSQL LibFileSystemAccessClient)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,37 +8,17 @@
|
|||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <FileSystemAccessServer/ClientConnection.h>
|
||||
#include <FileSystemAccessServer/FileSystemAccessClientEndpoint.h>
|
||||
#include <FileSystemAccessServer/FileSystemAccessServerEndpoint.h>
|
||||
#include <LibFileSystemAccessClient/Client.h>
|
||||
#include <LibGUI/ActionGroup.h>
|
||||
#include <LibGUI/Application.h>
|
||||
#include <LibGUI/Icon.h>
|
||||
#include <LibGUI/TextEditor.h>
|
||||
#include <LibGUI/Widget.h>
|
||||
#include <LibGUI/Window.h>
|
||||
#include <LibIPC/ServerConnection.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace TextEditor {
|
||||
|
||||
class FileSystemAccessClient final
|
||||
: public IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>
|
||||
, public FileSystemAccessClientEndpoint {
|
||||
C_OBJECT(FileSystemAccessClient)
|
||||
|
||||
public:
|
||||
virtual void die() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
explicit FileSystemAccessClient()
|
||||
: IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>(*this, "/tmp/portal/filesystemaccess")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MainWidget final : public GUI::Widget {
|
||||
C_OBJECT(MainWidget);
|
||||
|
||||
|
@ -74,8 +54,6 @@ private:
|
|||
|
||||
virtual void drop_event(GUI::DropEvent&) override;
|
||||
|
||||
NonnullRefPtr<FileSystemAccessClient> m_file_system_access_client;
|
||||
|
||||
RefPtr<GUI::TextEditor> m_editor;
|
||||
String m_path;
|
||||
String m_name;
|
||||
|
|
|
@ -14,6 +14,7 @@ add_subdirectory(LibDesktop)
|
|||
add_subdirectory(LibDiff)
|
||||
add_subdirectory(LibDl)
|
||||
add_subdirectory(LibELF)
|
||||
add_subdirectory(LibFileSystemAccessClient)
|
||||
add_subdirectory(LibGemini)
|
||||
add_subdirectory(LibGfx)
|
||||
add_subdirectory(LibGL)
|
||||
|
|
12
Userland/Libraries/LibFileSystemAccessClient/CMakeLists.txt
Normal file
12
Userland/Libraries/LibFileSystemAccessClient/CMakeLists.txt
Normal 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)
|
73
Userland/Libraries/LibFileSystemAccessClient/Client.cpp
Normal file
73
Userland/Libraries/LibFileSystemAccessClient/Client.cpp
Normal 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, {}, "");
|
||||
}
|
||||
|
||||
}
|
49
Userland/Libraries/LibFileSystemAccessClient/Client.h
Normal file
49
Userland/Libraries/LibFileSystemAccessClient/Client.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
|
@ -16,3 +16,4 @@ set(SOURCES
|
|||
|
||||
serenity_bin(FileSystemAccessServer)
|
||||
target_link_libraries(FileSystemAccessServer LibCore LibIPC LibGUI)
|
||||
add_dependencies(FileSystemAccessServer WindowServer)
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
* 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 <AK/Debug.h>
|
||||
#include <FileSystemAccessServer/ClientConnection.h>
|
||||
#include <LibCore/File.h>
|
||||
|
@ -33,7 +37,20 @@ void ClientConnection::die()
|
|||
exit(0);
|
||||
}
|
||||
|
||||
Messages::FileSystemAccessServer::RequestFileResponse ClientConnection::request_file(String const& path, Core::OpenMode const& requested_access)
|
||||
RefPtr<GUI::Window> ClientConnection::create_dummy_child_window(i32 window_server_client_id, i32 parent_window_id)
|
||||
{
|
||||
auto window = GUI::Window::construct();
|
||||
window->set_opacity(0);
|
||||
window->set_frameless(true);
|
||||
auto rect = GUI::WindowServerConnection::the().get_window_rect_from_client(window_server_client_id, parent_window_id);
|
||||
window->set_rect(rect);
|
||||
window->show();
|
||||
GUI::WindowServerConnection::the().async_set_window_parent_from_client(window_server_client_id, parent_window_id, window->window_id());
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
void ClientConnection::request_file(i32 window_server_client_id, i32 parent_window_id, String const& path, Core::OpenMode const& requested_access)
|
||||
{
|
||||
VERIFY(path.starts_with("/"sv));
|
||||
|
||||
|
@ -47,21 +64,23 @@ Messages::FileSystemAccessServer::RequestFileResponse ClientConnection::request_
|
|||
approved = has_flag(maybe_permissions.value(), relevant_permissions);
|
||||
|
||||
if (!approved) {
|
||||
StringBuilder builder;
|
||||
if (has_flag(requested_access, Core::OpenMode::ReadOnly))
|
||||
builder.append('r');
|
||||
String access_string;
|
||||
|
||||
if (has_flag(requested_access, Core::OpenMode::WriteOnly))
|
||||
builder.append('w');
|
||||
|
||||
auto access_string = builder.to_string();
|
||||
if (has_flag(requested_access, Core::OpenMode::ReadWrite))
|
||||
access_string = "read and write";
|
||||
else if (has_flag(requested_access, Core::OpenMode::ReadOnly))
|
||||
access_string = "read from";
|
||||
else if (has_flag(requested_access, Core::OpenMode::WriteOnly))
|
||||
access_string = "write to";
|
||||
|
||||
auto pid = this->socket().peer_pid();
|
||||
auto exe_link = LexicalPath("/proc").append(String::number(pid)).append("exe").string();
|
||||
auto exe_path = Core::File::real_path_for(exe_link);
|
||||
auto exe_name = LexicalPath::basename(exe_path);
|
||||
|
||||
auto result = GUI::MessageBox::show(nullptr, String::formatted("Give {} ({}) \"{}\" access to \"{}\"?", exe_name, pid, access_string, path), "File Permissions Requested", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::YesNo);
|
||||
auto main_window = create_dummy_child_window(window_server_client_id, parent_window_id);
|
||||
|
||||
auto result = GUI::MessageBox::show(main_window, String::formatted("Allow {} ({}) to {} \"{}\"?", exe_name, pid, access_string, path), "File Permissions Requested", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::YesNo);
|
||||
|
||||
approved = result == GUI::MessageBox::ExecYes;
|
||||
|
||||
|
@ -80,40 +99,40 @@ Messages::FileSystemAccessServer::RequestFileResponse ClientConnection::request_
|
|||
|
||||
if (file.is_error()) {
|
||||
dbgln("FileSystemAccessServer: Couldn't open {}, error {}", path, file.error());
|
||||
|
||||
return { errno, Optional<IPC::File> {} };
|
||||
async_handle_prompt_end(errno, Optional<IPC::File> {}, path);
|
||||
} else {
|
||||
async_handle_prompt_end(0, IPC::File(file.value()->leak_fd(), IPC::File::CloseAfterSending), path);
|
||||
}
|
||||
|
||||
return { 0, IPC::File(file.value()->leak_fd(), IPC::File::CloseAfterSending) };
|
||||
} else {
|
||||
async_handle_prompt_end(-1, Optional<IPC::File> {}, path);
|
||||
}
|
||||
|
||||
return { -1, Optional<IPC::File> {} };
|
||||
}
|
||||
|
||||
Messages::FileSystemAccessServer::PromptOpenFileResponse ClientConnection::prompt_open_file(String const& path_to_view, Core::OpenMode const& requested_access)
|
||||
void ClientConnection::prompt_open_file(i32 window_server_client_id, i32 parent_window_id, String const& path_to_view, Core::OpenMode const& requested_access)
|
||||
{
|
||||
auto relevant_permissions = requested_access & (Core::OpenMode::ReadOnly | Core::OpenMode::WriteOnly);
|
||||
VERIFY(relevant_permissions != Core::OpenMode::NotOpen);
|
||||
|
||||
auto main_window = GUI::Window::construct();
|
||||
auto main_window = create_dummy_child_window(window_server_client_id, parent_window_id);
|
||||
|
||||
auto user_picked_file = GUI::FilePicker::get_open_filepath(main_window, "Select file", path_to_view);
|
||||
|
||||
return prompt_helper<Messages::FileSystemAccessServer::PromptOpenFileResponse>(user_picked_file, requested_access);
|
||||
prompt_helper(user_picked_file, requested_access);
|
||||
}
|
||||
|
||||
Messages::FileSystemAccessServer::PromptSaveFileResponse ClientConnection::prompt_save_file(String const& name, String const& ext, String const& path_to_view, Core::OpenMode const& requested_access)
|
||||
void ClientConnection::prompt_save_file(i32 window_server_client_id, i32 parent_window_id, String const& name, String const& ext, String const& path_to_view, Core::OpenMode const& requested_access)
|
||||
{
|
||||
auto relevant_permissions = requested_access & (Core::OpenMode::ReadOnly | Core::OpenMode::WriteOnly);
|
||||
VERIFY(relevant_permissions != Core::OpenMode::NotOpen);
|
||||
|
||||
auto main_window = GUI::Window::construct();
|
||||
auto main_window = create_dummy_child_window(window_server_client_id, parent_window_id);
|
||||
|
||||
auto user_picked_file = GUI::FilePicker::get_save_filepath(main_window, name, ext, path_to_view);
|
||||
|
||||
return prompt_helper<Messages::FileSystemAccessServer::PromptSaveFileResponse>(user_picked_file, requested_access);
|
||||
prompt_helper(user_picked_file, requested_access);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ClientConnection::prompt_helper(Optional<String> const& user_picked_file, Core::OpenMode const& requested_access)
|
||||
void ClientConnection::prompt_helper(Optional<String> const& user_picked_file, Core::OpenMode const& requested_access)
|
||||
{
|
||||
if (user_picked_file.has_value()) {
|
||||
VERIFY(user_picked_file->starts_with("/"sv));
|
||||
|
@ -122,20 +141,20 @@ T ClientConnection::prompt_helper(Optional<String> const& user_picked_file, Core
|
|||
if (file.is_error()) {
|
||||
dbgln("FileSystemAccessServer: Couldn't open {}, error {}", user_picked_file.value(), file.error());
|
||||
|
||||
return { errno, Optional<IPC::File> {}, user_picked_file.value() };
|
||||
async_handle_prompt_end(errno, Optional<IPC::File> {}, user_picked_file);
|
||||
} else {
|
||||
auto maybe_permissions = m_approved_files.get(user_picked_file.value());
|
||||
auto new_permissions = requested_access & (Core::OpenMode::ReadOnly | Core::OpenMode::WriteOnly);
|
||||
if (maybe_permissions.has_value())
|
||||
new_permissions |= maybe_permissions.value();
|
||||
|
||||
m_approved_files.set(user_picked_file.value(), new_permissions);
|
||||
|
||||
async_handle_prompt_end(0, IPC::File(file.value()->leak_fd(), IPC::File::CloseAfterSending), user_picked_file);
|
||||
}
|
||||
|
||||
auto maybe_permissions = m_approved_files.get(user_picked_file.value());
|
||||
auto new_permissions = requested_access & (Core::OpenMode::ReadOnly | Core::OpenMode::WriteOnly);
|
||||
if (maybe_permissions.has_value())
|
||||
new_permissions |= maybe_permissions.value();
|
||||
|
||||
m_approved_files.set(user_picked_file.value(), new_permissions);
|
||||
|
||||
return { 0, IPC::File(file.value()->leak_fd(), IPC::File::CloseAfterSending), user_picked_file.value() };
|
||||
} else {
|
||||
async_handle_prompt_end(-1, Optional<IPC::File> {}, Optional<String> {});
|
||||
}
|
||||
|
||||
return { -1, Optional<IPC::File> {}, Optional<String> {} };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <FileSystemAccessServer/FileSystemAccessClientEndpoint.h>
|
||||
#include <FileSystemAccessServer/FileSystemAccessServerEndpoint.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibGUI/Forward.h>
|
||||
#include <LibIPC/ClientConnection.h>
|
||||
|
||||
namespace FileSystemAccessServer {
|
||||
|
@ -25,12 +26,12 @@ public:
|
|||
virtual void die() override;
|
||||
|
||||
private:
|
||||
virtual Messages::FileSystemAccessServer::RequestFileResponse request_file(String const&, Core::OpenMode const&) override;
|
||||
virtual Messages::FileSystemAccessServer::PromptOpenFileResponse prompt_open_file(String const&, Core::OpenMode const&) override;
|
||||
virtual Messages::FileSystemAccessServer::PromptSaveFileResponse prompt_save_file(String const&, String const&, String const&, Core::OpenMode const&) override;
|
||||
virtual void request_file(i32, i32, String const&, Core::OpenMode const&) override;
|
||||
virtual void prompt_open_file(i32, i32, String const&, Core::OpenMode const&) override;
|
||||
virtual void prompt_save_file(i32, i32, String const&, String const&, String const&, Core::OpenMode const&) override;
|
||||
|
||||
template<typename T>
|
||||
T prompt_helper(Optional<String> const&, Core::OpenMode const&);
|
||||
void prompt_helper(Optional<String> const&, Core::OpenMode const&);
|
||||
RefPtr<GUI::Window> create_dummy_child_window(i32, i32);
|
||||
|
||||
HashMap<String, Core::OpenMode> m_approved_files;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
endpoint FileSystemAccessClient
|
||||
{
|
||||
handle_prompt_end(i32 error, Optional<IPC::File> fd, Optional<String> chosen_file) =|
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
endpoint FileSystemAccessServer
|
||||
{
|
||||
request_file(String path, Core::OpenMode requested_access) => (i32 error, Optional<IPC::File> fd)
|
||||
prompt_open_file(String path_to_view, Core::OpenMode requested_access) => (i32 error, Optional<IPC::File> fd, Optional<String> chosen_file)
|
||||
prompt_save_file(String title, String ext, String path_to_view, Core::OpenMode requested_access) => (i32 error, Optional<IPC::File> fd, Optional<String> chosen_file)
|
||||
request_file(i32 window_server_client_id, i32 window_id, String path, Core::OpenMode requested_access) =|
|
||||
prompt_open_file(i32 window_server_client_id, i32 window_id, String path_to_view, Core::OpenMode requested_access) =|
|
||||
prompt_save_file(i32 window_server_client_id, i32 window_id,String title, String ext, String path_to_view, Core::OpenMode requested_access) =|
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue