diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index 1f69875976..ae648d4300 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -532,6 +532,22 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ [self reload]; }; + m_web_view_bridge->on_request_tooltip_override = [weak_self](auto, auto const& tooltip) { + LadybirdWebView* self = weak_self; + if (self == nil) { + return; + } + self.toolTip = Ladybird::string_to_ns_string(tooltip); + }; + + m_web_view_bridge->on_stop_tooltip_override = [weak_self]() { + LadybirdWebView* self = weak_self; + if (self == nil) { + return; + } + self.toolTip = nil; + }; + m_web_view_bridge->on_enter_tooltip_area = [weak_self](auto const& tooltip) { LadybirdWebView* self = weak_self; if (self == nil) { diff --git a/Ladybird/Qt/WebContentView.cpp b/Ladybird/Qt/WebContentView.cpp index 17b22c4338..b7a8980ee6 100644 --- a/Ladybird/Qt/WebContentView.cpp +++ b/Ladybird/Qt/WebContentView.cpp @@ -99,6 +99,24 @@ WebContentView::WebContentView(QWidget* window, WebContentOptions const& web_con update_cursor(cursor); }; + on_request_tooltip_override = [this](auto position, auto const& tooltip) { + m_tooltip_override = true; + if (m_tooltip_hover_timer.isActive()) + m_tooltip_hover_timer.stop(); + + auto tooltip_without_carriage_return = tooltip.contains("\r"sv) + ? tooltip.replace("\r\n"sv, "\n"sv, ReplaceMode::All).replace("\r"sv, "\n"sv, ReplaceMode::All) + : tooltip; + QToolTip::showText( + mapToGlobal(QPoint(position.x(), position.y())), + qstring_from_ak_string(tooltip_without_carriage_return), + this); + }; + + on_stop_tooltip_override = [this]() { + m_tooltip_override = false; + }; + on_enter_tooltip_area = [this](auto const& tooltip) { m_tooltip_text = tooltip.contains("\r"sv) ? tooltip.replace("\r\n"sv, "\n"sv, ReplaceMode::All).replace("\r"sv, "\n"sv, ReplaceMode::All) @@ -332,9 +350,11 @@ void WebContentView::keyReleaseEvent(QKeyEvent* event) void WebContentView::mouseMoveEvent(QMouseEvent* event) { - if (QToolTip::isVisible()) - QToolTip::hideText(); - m_tooltip_hover_timer.start(600); + if (!m_tooltip_override) { + if (QToolTip::isVisible()) + QToolTip::hideText(); + m_tooltip_hover_timer.start(600); + } enqueue_native_event(Web::MouseEvent::Type::MouseMove, *event); } diff --git a/Ladybird/Qt/WebContentView.h b/Ladybird/Qt/WebContentView.h index 29757fdf8a..83288e6837 100644 --- a/Ladybird/Qt/WebContentView.h +++ b/Ladybird/Qt/WebContentView.h @@ -104,6 +104,7 @@ private: void finish_handling_key_event(Web::KeyEvent const&); void update_screen_rects(); + bool m_tooltip_override { false }; Optional m_tooltip_text; QTimer m_tooltip_hover_timer; diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index 89b61bb0c2..e1067c2009 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -328,6 +328,8 @@ public: virtual void page_did_request_image_context_menu(CSSPixelPoint, URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers, Gfx::Bitmap const*) { } virtual void page_did_request_media_context_menu(CSSPixelPoint, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers, Page::MediaContextMenu) { } virtual void page_did_middle_click_link(URL::URL const&, [[maybe_unused]] ByteString const& target, [[maybe_unused]] unsigned modifiers) { } + virtual void page_did_request_tooltip_override(CSSPixelPoint, ByteString const&) { } + virtual void page_did_stop_tooltip_override() { } virtual void page_did_enter_tooltip_area(ByteString const&) { } virtual void page_did_leave_tooltip_area() { } virtual void page_did_hover_link(URL::URL const&) { } diff --git a/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp b/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp index d40168326a..8e28eb005c 100644 --- a/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/MediaPaintable.cpp @@ -302,7 +302,7 @@ MediaPaintable::DispatchEventOfSameName MediaPaintable::handle_mouseup(Badge(media_element.volume() * 100.0); - browsing_context().page().client().page_did_enter_tooltip_area(ByteString::formatted("{}%", volume)); + browsing_context().page().client().page_did_request_tooltip_override({ position.x(), cached_layout_boxes.volume_scrub_rect->y() }, ByteString::formatted("{}%", volume)); } break; diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index cf733a5497..a05abb99d4 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -163,6 +163,8 @@ public: Function on_refresh; Function on_favicon_change; Function on_cursor_change; + Function on_request_tooltip_override; + Function on_stop_tooltip_override; Function on_enter_tooltip_area; Function on_leave_tooltip_area; Function on_request_alert; diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index dc9251911f..7ff57eb2a6 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -170,6 +170,22 @@ void WebContentClient::did_change_url(u64 page_id, URL::URL const& url) } } +void WebContentClient::did_request_tooltip_override(u64 page_id, Gfx::IntPoint position, ByteString const& title) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_request_tooltip_override) + view->on_request_tooltip_override(view->to_widget_position(position), title); + } +} + +void WebContentClient::did_stop_tooltip_override(u64 page_id) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_stop_tooltip_override) + view->on_stop_tooltip_override(); + } +} + void WebContentClient::did_enter_tooltip_area(u64 page_id, ByteString const& title) { if (auto view = view_for_page_id(page_id); view.has_value()) { diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index fa204d4cb2..01ac7e43f4 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -55,6 +55,8 @@ private: virtual void did_layout(u64 page_id, Gfx::IntSize) override; virtual void did_change_title(u64 page_id, ByteString const&) override; virtual void did_change_url(u64 page_id, URL::URL const&) override; + virtual void did_request_tooltip_override(u64 page_id, Gfx::IntPoint, ByteString const&) override; + virtual void did_stop_tooltip_override(u64 page_id) override; virtual void did_enter_tooltip_area(u64 page_id, ByteString const&) override; virtual void did_leave_tooltip_area(u64 page_id) override; virtual void did_hover_link(u64 page_id, URL::URL const&) override; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index 6bb2b4e42c..4fb0df93cc 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -318,6 +318,17 @@ Gfx::IntRect PageClient::page_did_request_fullscreen_window() return client().did_request_fullscreen_window(m_id); } +void PageClient::page_did_request_tooltip_override(Web::CSSPixelPoint position, ByteString const& title) +{ + auto device_position = page().css_to_device_point(position); + client().async_did_request_tooltip_override(m_id, { device_position.x(), device_position.y() }, title); +} + +void PageClient::page_did_stop_tooltip_override() +{ + client().async_did_leave_tooltip_area(m_id); +} + void PageClient::page_did_enter_tooltip_area(ByteString const& title) { client().async_did_enter_tooltip_area(m_id, title); diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h index 7e40b083d5..a4a3cf2625 100644 --- a/Userland/Services/WebContent/PageClient.h +++ b/Userland/Services/WebContent/PageClient.h @@ -119,6 +119,8 @@ private: virtual Gfx::IntRect page_did_request_maximize_window() override; virtual Gfx::IntRect page_did_request_minimize_window() override; virtual Gfx::IntRect page_did_request_fullscreen_window() override; + virtual void page_did_request_tooltip_override(Web::CSSPixelPoint, ByteString const&) override; + virtual void page_did_stop_tooltip_override() override; virtual void page_did_enter_tooltip_area(ByteString const&) override; virtual void page_did_leave_tooltip_area() override; virtual void page_did_hover_link(URL::URL const&) override; diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index b1948d84ce..2e3b93f618 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -27,6 +27,8 @@ endpoint WebContentClient did_layout(u64 page_id, Gfx::IntSize content_size) =| did_change_title(u64 page_id, ByteString title) =| did_change_url(u64 page_id, URL::URL url) =| + did_request_tooltip_override(u64 page_id, Gfx::IntPoint position, ByteString title) =| + did_stop_tooltip_override(u64 page_id) =| did_enter_tooltip_area(u64 page_id, ByteString title) =| did_leave_tooltip_area(u64 page_id) =| did_hover_link(u64 page_id, URL::URL url) =|