From d6889ecf35949ef1c5f9b9a794db2f33c9106a45 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 11 Sep 2020 18:15:47 +0200 Subject: [PATCH] LibWeb: Allow layout nodes to receive and track mouse events To implement form controls internally in LibWeb (necessary for multi process forms), we'll need the ability to handle events since we can't rely on LibGUI widgets anymore. A LayoutNode can now override wants_mouse_events() and if it returns true, it will now receive mousedown, mousemove and mouseup events. :^) --- Libraries/LibWeb/Layout/LayoutNode.cpp | 12 +++++++ Libraries/LibWeb/Layout/LayoutNode.h | 6 ++++ Libraries/LibWeb/Page/EventHandler.cpp | 44 ++++++++++++++++++++++++++ Libraries/LibWeb/Page/EventHandler.h | 5 +++ 4 files changed, 67 insertions(+) diff --git a/Libraries/LibWeb/Layout/LayoutNode.cpp b/Libraries/LibWeb/Layout/LayoutNode.cpp index 5bd0aebd64..c44e886d8f 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.cpp +++ b/Libraries/LibWeb/Layout/LayoutNode.cpp @@ -254,4 +254,16 @@ void LayoutNodeWithStyle::apply_style(const CSS::StyleProperties& specified_styl style.border_bottom().color = specified_style.color_or_fallback(CSS::PropertyID::BorderBottomColor, document(), Color::Transparent); } +void LayoutNode::handle_mousedown(Badge, const Gfx::IntPoint&, unsigned, unsigned) +{ +} + +void LayoutNode::handle_mouseup(Badge, const Gfx::IntPoint&, unsigned, unsigned) +{ +} + +void LayoutNode::handle_mousemove(Badge, const Gfx::IntPoint&, unsigned, unsigned) +{ +} + } diff --git a/Libraries/LibWeb/Layout/LayoutNode.h b/Libraries/LibWeb/Layout/LayoutNode.h index 246d40761f..b9cc0136ad 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.h +++ b/Libraries/LibWeb/Layout/LayoutNode.h @@ -99,6 +99,12 @@ public: bool is_inline_block() const { return is_inline() && is_block(); } + virtual bool wants_mouse_events() const { return false; } + + virtual void handle_mousedown(Badge, const Gfx::IntPoint&, unsigned button, unsigned modifiers); + virtual void handle_mouseup(Badge, const Gfx::IntPoint&, unsigned button, unsigned modifiers); + virtual void handle_mousemove(Badge, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers); + enum class LayoutMode { Default, AllPossibleLineBreaks, diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 32b750a821..57b73c9673 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -75,9 +75,20 @@ bool EventHandler::handle_mouseup(const Gfx::IntPoint& position, unsigned button { if (!layout_root()) return false; + + if (m_mouse_event_tracking_layout_node) { + m_mouse_event_tracking_layout_node->handle_mouseup({}, position, button, modifiers); + return true; + } + bool handled_event = false; auto result = layout_root()->hit_test(position, HitTestType::Exact); + + if (result.layout_node && result.layout_node->wants_mouse_events()) { + result.layout_node->handle_mouseup({}, position, button, modifiers); + } + if (result.layout_node && result.layout_node->node()) { RefPtr node = result.layout_node->node(); if (is(*node)) { @@ -101,6 +112,12 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt { if (!layout_root()) return false; + + if (m_mouse_event_tracking_layout_node) { + m_mouse_event_tracking_layout_node->handle_mousedown({}, position, button, modifiers); + return true; + } + NonnullRefPtr document = *m_frame.document(); auto& page_client = m_frame.page().client(); @@ -108,6 +125,11 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt if (!result.layout_node) return false; + if (result.layout_node->wants_mouse_events()) { + result.layout_node->handle_mousedown({}, position, button, modifiers); + return true; + } + RefPtr node = result.layout_node->node(); document->set_hovered_node(node); if (!node) @@ -171,6 +193,12 @@ bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned butt { if (!layout_root()) return false; + + if (m_mouse_event_tracking_layout_node) { + m_mouse_event_tracking_layout_node->handle_mousemove({}, position, buttons, modifiers); + return true; + } + auto& document = *m_frame.document(); auto& page_client = m_frame.page().client(); @@ -180,6 +208,14 @@ bool EventHandler::handle_mousemove(const Gfx::IntPoint& position, unsigned butt auto result = layout_root()->hit_test(position, HitTestType::Exact); const HTML::HTMLAnchorElement* hovered_link_element = nullptr; if (result.layout_node) { + + if (result.layout_node->wants_mouse_events()) { + result.layout_node->handle_mousemove({}, position, buttons, modifiers); + // FIXME: It feels a bit aggressive to always update the cursor like this. + page_client.page_did_request_cursor_change(Gfx::StandardCursor::None); + return true; + } + RefPtr node = result.layout_node->node(); if (node && is(*node)) { @@ -313,4 +349,12 @@ bool EventHandler::handle_keydown(KeyCode key, unsigned modifiers, u32 code_poin return false; } +void EventHandler::set_mouse_event_tracking_layout_node(LayoutNode* layout_node) +{ + if (layout_node) + m_mouse_event_tracking_layout_node = layout_node->make_weak_ptr(); + else + m_mouse_event_tracking_layout_node = nullptr; +} + } diff --git a/Libraries/LibWeb/Page/EventHandler.h b/Libraries/LibWeb/Page/EventHandler.h index 37350184bc..e077a71ded 100644 --- a/Libraries/LibWeb/Page/EventHandler.h +++ b/Libraries/LibWeb/Page/EventHandler.h @@ -27,6 +27,7 @@ #pragma once #include +#include #include #include #include @@ -47,6 +48,8 @@ public: bool handle_keydown(KeyCode, unsigned modifiers, u32 code_point); + void set_mouse_event_tracking_layout_node(LayoutNode*); + private: bool focus_next_element(); bool focus_previous_element(); @@ -59,6 +62,8 @@ private: Frame& m_frame; bool m_in_mouse_selection { false }; + + WeakPtr m_mouse_event_tracking_layout_node; }; }