diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index 820ca3cc940..be549e9f5df 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -599,6 +599,16 @@ ErrorOr Application::path_for_downloaded_file(StringView file) cons return LexicalPath::join(downloads_directory, file); } +void Application::display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const +{ + outln("{} saved to: {}", download_name, path); +} + +void Application::display_error_dialog(StringView error_message) const +{ + warnln("{}", error_message); +} + ErrorOr Application::toggle_devtools_enabled() { if (m_devtools) { diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index 96d1013d1c6..9ad62a38dd4 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -53,6 +53,7 @@ public: static ProcessManager& process_manager() { return *the().m_process_manager; } ErrorOr> launch_web_content_process(ViewImplementation&); + virtual Optional active_web_view() const { return {}; } void add_child_process(Process&&); @@ -64,6 +65,9 @@ public: ErrorOr path_for_downloaded_file(StringView file) const; + virtual void display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const; + virtual void display_error_dialog(StringView error_message) const; + enum class DevtoolsState { Disabled, Enabled, diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index 73a2db2ef56..ed2c84ac920 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -231,6 +231,7 @@ public: Function const& total_match_count)> on_find_in_page; Function on_theme_color_change; Function on_insert_clipboard_entry; + Function on_request_clipboard_text; Function on_request_clipboard_entries; Function on_audio_play_state_changed; Function on_navigation_buttons_state_changed; diff --git a/UI/AppKit/Application/Application.h b/UI/AppKit/Application/Application.h index ad0f07ab431..28d07c41faf 100644 --- a/UI/AppKit/Application/Application.h +++ b/UI/AppKit/Application/Application.h @@ -18,8 +18,13 @@ class Application final : public WebView::Application { private: explicit Application(); - virtual Optional ask_user_for_download_folder() const override; virtual NonnullOwnPtr create_platform_event_loop() override; + + virtual Optional active_web_view() const override; + + virtual Optional ask_user_for_download_folder() 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; }; } diff --git a/UI/AppKit/Application/Application.mm b/UI/AppKit/Application/Application.mm index 4fbdb2c85b9..b26fa9c5b51 100644 --- a/UI/AppKit/Application/Application.mm +++ b/UI/AppKit/Application/Application.mm @@ -10,6 +10,9 @@ #include #import +#import +#import +#import #if !__has_feature(objc_arc) # error "This project requires ARC" @@ -19,6 +22,25 @@ namespace Ladybird { Application::Application() = default; +NonnullOwnPtr Application::create_platform_event_loop() +{ + if (!browser_options().headless_mode.has_value()) { + Core::EventLoopManager::install(*new WebView::EventLoopManagerMacOS); + [::Application sharedApplication]; + } + + return WebView::Application::create_platform_event_loop(); +} + +Optional Application::active_web_view() const +{ + ApplicationDelegate* delegate = [NSApp delegate]; + + if (auto* tab = [delegate activeTab]) + return [[tab web_view] view]; + return {}; +} + Optional Application::ask_user_for_download_folder() const { auto* panel = [NSOpenPanel openPanel]; @@ -33,14 +55,36 @@ Optional Application::ask_user_for_download_folder() const return Ladybird::ns_string_to_byte_string([[panel URL] path]); } -NonnullOwnPtr Application::create_platform_event_loop() +void Application::display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const { - if (!browser_options().headless_mode.has_value()) { - Core::EventLoopManager::install(*new WebView::EventLoopManagerMacOS); - [::Application sharedApplication]; - } + ApplicationDelegate* delegate = [NSApp delegate]; - return WebView::Application::create_platform_event_loop(); + auto message = MUST(String::formatted("{} saved to: {}", download_name, path)); + + auto* dialog = [[NSAlert alloc] init]; + [dialog setMessageText:Ladybird::string_to_ns_string(message)]; + [[dialog addButtonWithTitle:@"OK"] setTag:NSModalResponseOK]; + [[dialog addButtonWithTitle:@"Open folder"] setTag:NSModalResponseContinue]; + + __block auto* ns_path = Ladybird::string_to_ns_string(path.string()); + + [dialog beginSheetModalForWindow:[delegate activeTab] + completionHandler:^(NSModalResponse response) { + if (response == NSModalResponseContinue) { + [[NSWorkspace sharedWorkspace] selectFile:ns_path inFileViewerRootedAtPath:@""]; + } + }]; +} + +void Application::display_error_dialog(StringView error_message) const +{ + ApplicationDelegate* delegate = [NSApp delegate]; + + auto* dialog = [[NSAlert alloc] init]; + [dialog setMessageText:Ladybird::string_to_ns_string(error_message)]; + + [dialog beginSheetModalForWindow:[delegate activeTab] + completionHandler:nil]; } } diff --git a/UI/AppKit/Interface/LadybirdWebView.mm b/UI/AppKit/Interface/LadybirdWebView.mm index fd8e135fe7b..13f3ab458cb 100644 --- a/UI/AppKit/Interface/LadybirdWebView.mm +++ b/UI/AppKit/Interface/LadybirdWebView.mm @@ -1085,6 +1085,14 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ copy_data_to_clipboard(entry.data, pasteboard_type); }; + m_web_view_bridge->on_request_clipboard_text = []() { + auto* paste_board = [NSPasteboard generalPasteboard]; + + if (auto* contents = [paste_board stringForType:NSPasteboardTypeString]) + return Ladybird::ns_string_to_string(contents); + return String {}; + }; + m_web_view_bridge->on_request_clipboard_entries = [weak_self](auto request_id) { LadybirdWebView* self = weak_self; if (self == nil) { @@ -1154,11 +1162,8 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ - (void)paste:(id)sender { - auto* paste_board = [NSPasteboard generalPasteboard]; - - if (auto* contents = [paste_board stringForType:NSPasteboardTypeString]) { - m_web_view_bridge->paste(Ladybird::ns_string_to_string(contents)); - } + if (m_web_view_bridge->on_request_clipboard_text) + m_web_view_bridge->paste(m_web_view_bridge->on_request_clipboard_text()); } - (void)selectAll:(id)sender @@ -1191,34 +1196,15 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ - (void)takeScreenshot:(WebView::ViewImplementation::ScreenshotType)type { m_web_view_bridge->take_screenshot(type) - ->when_resolved([self](auto const& path) { - auto message = MUST(String::formatted("Screenshot saved to: {}", path)); - - auto* dialog = [[NSAlert alloc] init]; - [dialog setMessageText:Ladybird::string_to_ns_string(message)]; - [[dialog addButtonWithTitle:@"OK"] setTag:NSModalResponseOK]; - [[dialog addButtonWithTitle:@"Open folder"] setTag:NSModalResponseContinue]; - - __block auto* ns_path = Ladybird::string_to_ns_string(path.string()); - - [dialog beginSheetModalForWindow:[self window] - completionHandler:^(NSModalResponse response) { - if (response == NSModalResponseContinue) { - [[NSWorkspace sharedWorkspace] selectFile:ns_path inFileViewerRootedAtPath:@""]; - } - }]; + ->when_resolved([](auto const& path) { + WebView::Application::the().display_download_confirmation_dialog("Screenshot"sv, path); }) - .when_rejected([self](auto const& error) { + .when_rejected([](auto const& error) { if (error.is_errno() && error.code() == ECANCELED) return; auto error_message = MUST(String::formatted("{}", error)); - - auto* dialog = [[NSAlert alloc] init]; - [dialog setMessageText:Ladybird::string_to_ns_string(error_message)]; - - [dialog beginSheetModalForWindow:[self window] - completionHandler:nil]; + WebView::Application::the().display_error_dialog(error_message); }); } diff --git a/UI/Qt/Application.cpp b/UI/Qt/Application.cpp index 19d498901da..e2ddf224385 100644 --- a/UI/Qt/Application.cpp +++ b/UI/Qt/Application.cpp @@ -11,8 +11,10 @@ #include #include +#include #include #include +#include namespace Ladybird { @@ -88,6 +90,13 @@ BrowserWindow& Application::new_window(Vector const& initial_urls, Bro return *window; } +Optional Application::active_web_view() const +{ + if (auto* active_tab = this->active_tab()) + return active_tab->view(); + return {}; +} + Optional Application::ask_user_for_download_folder() const { auto path = QFileDialog::getExistingDirectory(nullptr, "Select download directory", QDir::homePath()); @@ -97,4 +106,26 @@ Optional Application::ask_user_for_download_folder() const return ak_byte_string_from_qstring(path); } +void Application::display_download_confirmation_dialog(StringView download_name, LexicalPath const& path) const +{ + auto message = MUST(String::formatted("{} saved to: {}", download_name, path)); + + QMessageBox dialog(active_tab()); + dialog.setWindowTitle("Ladybird"); + dialog.setIcon(QMessageBox::Information); + dialog.setText(qstring_from_ak_string(message)); + dialog.addButton(QMessageBox::Ok); + dialog.addButton(QMessageBox::Open)->setText("Open folder"); + + if (dialog.exec() == QMessageBox::Open) { + auto path_url = QUrl::fromLocalFile(qstring_from_ak_string(path.dirname())); + QDesktopServices::openUrl(path_url); + } +} + +void Application::display_error_dialog(StringView error_message) const +{ + QMessageBox::warning(active_tab(), "Ladybird", qstring_from_ak_string(error_message)); +} + } diff --git a/UI/Qt/Application.h b/UI/Qt/Application.h index e9b6071c7e7..82be620b5ee 100644 --- a/UI/Qt/Application.h +++ b/UI/Qt/Application.h @@ -25,16 +25,22 @@ public: BrowserWindow& new_window(Vector const& initial_urls, BrowserWindow::IsPopupWindow is_popup_window = BrowserWindow::IsPopupWindow::No, Tab* parent_tab = nullptr, Optional page_index = {}); - BrowserWindow& active_window() { return *m_active_window; } + BrowserWindow& active_window() const { return *m_active_window; } void set_active_window(BrowserWindow& w) { m_active_window = &w; } + Tab* active_tab() const { return m_active_window ? m_active_window->current_tab() : nullptr; } + private: explicit Application(); virtual void create_platform_options(WebView::BrowserOptions&, WebView::WebContentOptions&) override; virtual NonnullOwnPtr create_platform_event_loop() override; + virtual Optional active_web_view() const override; + virtual Optional ask_user_for_download_folder() 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; OwnPtr m_application; BrowserWindow* m_active_window { nullptr }; diff --git a/UI/Qt/BrowserWindow.cpp b/UI/Qt/BrowserWindow.cpp index 111acc671b0..ffb21e0d498 100644 --- a/UI/Qt/BrowserWindow.cpp +++ b/UI/Qt/BrowserWindow.cpp @@ -1139,8 +1139,8 @@ void BrowserWindow::paste() if (!m_current_tab) return; - auto* clipboard = QGuiApplication::clipboard(); - m_current_tab->view().paste(ak_string_from_qstring(clipboard->text())); + if (m_current_tab->view().on_request_clipboard_text) + m_current_tab->view().paste(m_current_tab->view().on_request_clipboard_text()); } void BrowserWindow::update_displayed_zoom_level() diff --git a/UI/Qt/Tab.cpp b/UI/Qt/Tab.cpp index fe892fd59d1..b3c925329b4 100644 --- a/UI/Qt/Tab.cpp +++ b/UI/Qt/Tab.cpp @@ -380,6 +380,11 @@ Tab::Tab(BrowserWindow* window, RefPtr parent_client, clipboard->setMimeData(mime_data); }; + view().on_request_clipboard_text = []() { + auto const* clipboard = QGuiApplication::clipboard(); + return ak_string_from_qstring(clipboard->text()); + }; + view().on_request_clipboard_entries = [this](auto request_id) { auto const* clipboard = QGuiApplication::clipboard(); @@ -496,27 +501,15 @@ Tab::Tab(BrowserWindow* window, RefPtr parent_client, auto& view = this->view(); view.take_screenshot(type) - ->when_resolved([this](auto const& path) { - auto message = MUST(String::formatted("Screenshot saved to: {}", path)); - - QMessageBox dialog(this); - dialog.setWindowTitle("Ladybird"); - dialog.setIcon(QMessageBox::Information); - dialog.setText(qstring_from_ak_string(message)); - dialog.addButton(QMessageBox::Ok); - dialog.addButton(QMessageBox::Open)->setText("Open folder"); - - if (dialog.exec() == QMessageBox::Open) { - auto path_url = QUrl::fromLocalFile(qstring_from_ak_string(path.dirname())); - QDesktopServices::openUrl(path_url); - } + ->when_resolved([](auto const& path) { + WebView::Application::the().display_download_confirmation_dialog("Screenshot"sv, path); }) - .when_rejected([this](auto const& error) { + .when_rejected([](auto const& error) { if (error.is_errno() && error.code() == ECANCELED) return; auto error_message = MUST(String::formatted("{}", error)); - QMessageBox::warning(this, "Ladybird", qstring_from_ak_string(error_message)); + WebView::Application::the().display_error_dialog(error_message); }); };