LibWebView+UI: Always ask the user where to save screenshots

We currently always save screenshots to the Downloads folder. We will
now always ask for a save location.

This will just let an upcoming feature to save images from web pages
behave the same way. We will want the user to be able to choose a file
name, since the file name from the URL might be nonsense or already
exist.
This commit is contained in:
Timothy Flynn 2026-02-02 18:54:59 -05:00 committed by Tim Flynn
parent 4a3a96b913
commit 70482687a2
6 changed files with 27 additions and 24 deletions

View file

@ -629,25 +629,22 @@ void Application::process_did_exit(Process&& process)
ErrorOr<LexicalPath> Application::path_for_downloaded_file(StringView file) const
{
auto downloads_directory = Core::StandardPaths::downloads_directory();
if (browser_options().headless_mode.has_value()) {
auto downloads_directory = Core::StandardPaths::downloads_directory();
if (!FileSystem::is_directory(downloads_directory)) {
if (browser_options().headless_mode.has_value()) {
if (!FileSystem::is_directory(downloads_directory)) {
dbgln("Unable to ask user for download folder in headless mode, please ensure {} is a directory or use the XDG_DOWNLOAD_DIR environment variable to set a new download directory", downloads_directory);
return Error::from_errno(ENOENT);
}
auto maybe_downloads_directory = ask_user_for_download_folder();
if (!maybe_downloads_directory.has_value())
return Error::from_errno(ECANCELED);
downloads_directory = maybe_downloads_directory.release_value();
return LexicalPath::join(downloads_directory, file);
}
if (!FileSystem::is_directory(downloads_directory))
return Error::from_errno(ENOENT);
auto download_path = ask_user_for_download_path(file);
if (!download_path.has_value())
return Error::from_errno(ECANCELED);
return LexicalPath::join(downloads_directory, file);
return LexicalPath { download_path.release_value() };
}
void Application::display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const

View file

@ -144,7 +144,7 @@ protected:
virtual void create_platform_options(BrowserOptions&, RequestServerOptions&, WebContentOptions&) { }
virtual NonnullOwnPtr<Core::EventLoop> create_platform_event_loop();
virtual Optional<ByteString> ask_user_for_download_folder() const { return {}; }
virtual Optional<ByteString> ask_user_for_download_path([[maybe_unused]] StringView file) const { return {}; }
virtual void on_devtools_enabled() const;
virtual void on_devtools_disabled() const;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2025, Tim Flynn <trflynn89@ladybird.org>
* Copyright (c) 2023-2026, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -23,7 +23,7 @@ private:
virtual Optional<WebView::ViewImplementation&> active_web_view() const override;
virtual Optional<WebView::ViewImplementation&> open_blank_new_tab(Web::HTML::ActivateTab) const override;
virtual Optional<ByteString> ask_user_for_download_folder() const override;
virtual Optional<ByteString> ask_user_for_download_path(StringView file) const override;
virtual void display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const override;
virtual void display_error_dialog(StringView error_message) const override;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2025, Tim Flynn <trflynn89@ladybird.org>
* Copyright (c) 2023-2026, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -52,13 +52,11 @@ Optional<WebView::ViewImplementation&> Application::open_blank_new_tab(Web::HTML
return [[tab web_view] view];
}
Optional<ByteString> Application::ask_user_for_download_folder() const
Optional<ByteString> Application::ask_user_for_download_path(StringView file) const
{
auto* panel = [NSOpenPanel openPanel];
[panel setAllowsMultipleSelection:NO];
[panel setCanChooseDirectories:YES];
[panel setCanChooseFiles:NO];
[panel setMessage:@"Select download directory"];
auto* panel = [NSSavePanel savePanel];
[panel setNameFieldStringValue:Ladybird::string_to_ns_string(file)];
[panel setTitle:@"Select save location"];
if ([panel runModal] != NSModalResponseOK)
return {};

View file

@ -17,6 +17,7 @@
#include <QFileOpenEvent>
#include <QMessageBox>
#include <QMimeData>
#include <QStandardPaths>
#if defined(AK_OS_WINDOWS)
# include <AK/Windows.h>
@ -144,9 +145,16 @@ Optional<WebView::ViewImplementation&> Application::open_blank_new_tab(Web::HTML
return tab.view();
}
Optional<ByteString> Application::ask_user_for_download_folder() const
Optional<ByteString> Application::ask_user_for_download_path(StringView file) const
{
auto path = QFileDialog::getExistingDirectory(nullptr, "Select download directory", QDir::homePath());
auto default_path = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
if (default_path.isNull() || default_path.isEmpty())
default_path = qstring_from_ak_string(file);
else
default_path = QDir { default_path }.filePath(qstring_from_ak_string(file));
auto path = QFileDialog::getSaveFileName(nullptr, "Select save location", default_path);
if (path.isNull())
return {};

View file

@ -39,7 +39,7 @@ private:
virtual Optional<WebView::ViewImplementation&> active_web_view() const override;
virtual Optional<WebView::ViewImplementation&> open_blank_new_tab(Web::HTML::ActivateTab) const override;
virtual Optional<ByteString> ask_user_for_download_folder() const override;
virtual Optional<ByteString> ask_user_for_download_path(StringView file) const override;
virtual void display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const override;
virtual void display_error_dialog(StringView error_message) const override;