| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_ |
| #define UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_ |
| |
| #include <deque> |
| #include <memory> |
| #include <optional> |
| #include <ostream> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/time/time.h" |
| #include "ui/events/event.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/keycodes/dom/dom_code.h" |
| #include "ui/events/platform/platform_event_source.h" |
| #include "ui/events/pointer_details.h" |
| #include "ui/events/types/event_type.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/ozone/platform/wayland/common/wayland_util.h" |
| #include "ui/ozone/platform/wayland/host/wayland_input_method_context.h" |
| #include "ui/ozone/platform/wayland/host/wayland_keyboard.h" |
| #include "ui/ozone/platform/wayland/host/wayland_pointer.h" |
| #include "ui/ozone/platform/wayland/host/wayland_tablet_tool.h" |
| #include "ui/ozone/platform/wayland/host/wayland_touch.h" |
| #include "ui/ozone/platform/wayland/host/wayland_window_observer.h" |
| #include "ui/ozone/platform/wayland/host/wayland_zwp_pointer_gestures.h" |
| #include "ui/ozone/platform/wayland/host/wayland_zwp_relative_pointer_manager.h" |
| |
| struct wl_display; |
| |
| namespace gfx { |
| class Vector2dF; |
| } |
| |
| namespace ui { |
| |
| class WaylandConnection; |
| class WaylandWindow; |
| class WaylandWindowManager; |
| class WaylandEventWatcher; |
| |
| // Wayland implementation of ui::PlatformEventSource. It polls for events |
| // through WaylandEventWatcher and centralizes the input and focus handling |
| // logic within Ozone Wayland backend. In order to do so, it also implements the |
| // input objects' delegate interfaces, which are the entry point of event data |
| // coming from input devices, e.g: wl_{keyboard,pointer,touch}, which are then |
| // pre-processed, translated into ui::Event instances and dispatched to the |
| // PlatformEvent system. |
| class WaylandEventSource : public PlatformEventSource, |
| public WaylandWindowObserver, |
| public WaylandKeyboard::Delegate, |
| public WaylandPointer::Delegate, |
| public WaylandTabletTool::Delegate, |
| public WaylandTouch::Delegate, |
| public WaylandZwpPointerGestures::Delegate, |
| public WaylandZwpRelativePointerManager::Delegate { |
| public: |
| static void ConvertEventToTarget(EventTarget* new_target, |
| LocatedEvent* event); |
| |
| WaylandEventSource(wl_display* display, |
| wl_event_queue* event_queue, |
| WaylandWindowManager* window_manager, |
| WaylandConnection* connection, |
| bool use_threaded_polling = false); |
| WaylandEventSource(const WaylandEventSource&) = delete; |
| WaylandEventSource& operator=(const WaylandEventSource&) = delete; |
| ~WaylandEventSource() override; |
| |
| int last_pointer_button_pressed() const { |
| return last_pointer_button_pressed_; |
| } |
| |
| int keyboard_modifiers() const { return keyboard_modifiers_; } |
| |
| // Sets a callback that that shutdowns the browser in case of unrecoverable |
| // error. Called by WaylandEventWatcher. |
| void SetShutdownCb(base::OnceCallback<void()> shutdown_cb); |
| |
| // Starts polling for events from the wayland connection file descriptor. |
| // This method assumes connection is already established and input objects |
| // are already bound and properly initialized. |
| void StartProcessingEvents(); |
| |
| // Forwards the call to WaylandEventWatcher, which calls |
| // wl_display_roundtrip_queue. |
| void RoundTripQueue(); |
| |
| void DumpState(std::ostream& out) const; |
| |
| void ResetStateForTesting() override; |
| |
| // WaylandKeyboard::Delegate |
| void OnKeyboardFocusChanged(WaylandWindow* window, bool focused) override; |
| void OnKeyboardModifiersChanged(int modifiers) override; |
| uint32_t OnKeyboardKeyEvent(EventType type, |
| DomCode dom_code, |
| bool repeat, |
| std::optional<uint32_t> serial, |
| base::TimeTicks timestamp, |
| int device_id, |
| WaylandKeyboard::KeyEventKind kind) override; |
| void OnSynthesizedKeyPressEvent(WaylandWindow* window, |
| DomCode dom_code, |
| base::TimeTicks timestamp) override; |
| |
| // WaylandPointer::Delegate |
| void OnPointerFocusChanged(WaylandWindow* window, |
| const gfx::PointF& location, |
| base::TimeTicks timestamp, |
| wl::EventDispatchPolicy dispatch_policy) override; |
| void OnPointerButtonEvent(EventType evtype, |
| int changed_button, |
| base::TimeTicks timestamp, |
| WaylandWindow* window, |
| wl::EventDispatchPolicy dispatch_policy, |
| bool allow_release_of_unpressed_button, |
| bool is_synthesized) override; |
| void OnPointerMotionEvent(const gfx::PointF& location, |
| base::TimeTicks timestamp, |
| wl::EventDispatchPolicy dispatch_policy, |
| bool is_synthesized) override; |
| void OnPointerAxisEvent(const gfx::Vector2dF& offset, |
| std::optional<base::TimeTicks> timestamp, |
| bool is_high_resolution) override; |
| void OnPointerFrameEvent() override; |
| void OnPointerAxisSourceEvent(uint32_t axis_source) override; |
| void OnPointerAxisStopEvent(uint32_t axis, |
| base::TimeTicks timestamp) override; |
| const gfx::PointF& GetPointerLocation() const override; |
| bool IsPointerButtonPressed(EventFlags button) const override; |
| void ReleasePressedPointerButtons(WaylandWindow* window, |
| base::TimeTicks timestamp) override; |
| |
| // WaylandTabletTool::Delegate: |
| void OnTabletToolProximityIn(WaylandWindow* window, |
| const gfx::PointF& location, |
| const PointerDetails& details, |
| base::TimeTicks time) override; |
| void OnTabletToolProximityOut(base::TimeTicks time) override; |
| void OnTabletToolMotion(const gfx::PointF& location, |
| const PointerDetails& details, |
| base::TimeTicks time) override; |
| void OnTabletToolButton(int32_t button, |
| bool pressed, |
| const PointerDetails& details, |
| base::TimeTicks time) override; |
| |
| // WaylandTouch::Delegate |
| void OnTouchPressEvent(WaylandWindow* window, |
| const gfx::PointF& location, |
| base::TimeTicks timestamp, |
| PointerId id, |
| wl::EventDispatchPolicy dispatch_policy) override; |
| void OnTouchReleaseEvent(base::TimeTicks timestamp, |
| PointerId id, |
| wl::EventDispatchPolicy dispatch_policy, |
| bool is_synthesized) override; |
| void OnTouchMotionEvent(const gfx::PointF& location, |
| base::TimeTicks timestamp, |
| PointerId id, |
| wl::EventDispatchPolicy dispatch_policy, |
| bool is_synthesized) override; |
| void OnTouchCancelEvent() override; |
| void OnTouchFrame() override; |
| void OnTouchFocusChanged(WaylandWindow* window) override; |
| std::vector<PointerId> GetActiveTouchPointIds() override; |
| const WaylandWindow* GetTouchTarget(PointerId id) const override; |
| |
| // WaylandZwpPointerGesture::Delegate: |
| void OnPinchEvent(EventType event_type, |
| const gfx::Vector2dF& delta, |
| base::TimeTicks timestamp, |
| int device_id, |
| std::optional<float> scale_delta) override; |
| void OnHoldEvent(EventType event_type, |
| uint32_t finger_count, |
| base::TimeTicks timestamp, |
| int device_id, |
| wl::EventDispatchPolicy dispatch_policy) override; |
| |
| // WaylandZwpRelativePointerManager::Delegate: |
| void SetRelativePointerMotionEnabled(bool enabled) override; |
| void OnRelativePointerMotion(const gfx::Vector2dF& delta, |
| base::TimeTicks timestamp) override; |
| |
| private: |
| struct PointerScrollData { |
| PointerScrollData(); |
| PointerScrollData(const PointerScrollData& other); |
| PointerScrollData(PointerScrollData&&); |
| ~PointerScrollData(); |
| |
| PointerScrollData& operator=(const PointerScrollData&); |
| PointerScrollData& operator=(PointerScrollData&&); |
| |
| std::optional<uint32_t> axis_source; |
| float dx = 0.0f; |
| float dy = 0.0f; |
| base::TimeDelta dt; |
| bool is_axis_stop = false; |
| bool is_high_resolution = false; |
| std::optional<base::TimeTicks> timestamp; |
| |
| void DumpState(std::ostream& out) const; |
| }; |
| |
| struct FrameData { |
| FrameData(const Event& event, base::OnceCallback<void()> completion_cb); |
| FrameData(const FrameData& other) = delete; |
| FrameData(FrameData&&) = delete; |
| ~FrameData(); |
| |
| std::unique_ptr<Event> event; |
| base::OnceCallback<void()> completion_cb; |
| |
| void DumpState(std::ostream& out) const; |
| }; |
| |
| // PlatformEventSource: |
| void OnDispatcherListChanged() override; |
| |
| // WaylandWindowObserver: |
| void OnWindowRemoved(WaylandWindow* window) override; |
| |
| void HandleTouchFocusChange(WaylandWindow* window, |
| bool focused, |
| std::optional<PointerId> id = std::nullopt); |
| bool ShouldUnsetTouchFocus(WaylandWindow* window, PointerId id); |
| |
| // Computes initial velocity of fling scroll based on recent frames. |
| // The fling velocity is computed the same way as in libgestures. |
| gfx::Vector2dF ComputeFlingVelocity(); |
| |
| // Wrap up method to support async pointer down/up event processing. |
| void OnPointerButtonEventInternal(WaylandWindow* window, EventType type); |
| |
| // Wrap up method to support async touch release processing. |
| void OnTouchReleaseInternal(PointerId id); |
| |
| // Ensure a valid instance of the PointerScrollData class member. |
| void EnsurePointerScrollData(const std::optional<base::TimeTicks>& timestamp); |
| |
| void ProcessPointerScrollData(); |
| |
| // Set the target to the event, then dispatch the event. |
| void SetTargetAndDispatchEvent(Event* event, EventTarget* target); |
| |
| // Find and set the target for the touch event, then dispatch the event. |
| void SetTouchTargetAndDispatchTouchEvent(TouchEvent* event); |
| |
| const raw_ptr<WaylandWindowManager> window_manager_; |
| |
| const raw_ptr<WaylandConnection> connection_; |
| |
| // Bitmask of EventFlags used to keep track of the the pointer state. |
| int pointer_flags_ = 0; |
| |
| // Bitmask of EventFlags used to keep track of the last changed button. |
| int last_pointer_button_pressed_ = 0; |
| |
| // Bitmask of EventFlags used to keep track of the the keyboard state. |
| // See ui/events/event_constants.h for examples and details. |
| int keyboard_modifiers_ = 0; |
| |
| // Last known pointer location. |
| gfx::PointF pointer_location_; |
| |
| // Last known relative pointer location (used for pointer lock). |
| std::optional<gfx::PointF> relative_pointer_location_; |
| |
| // Accumulates the scroll data within a pointer frame internal. |
| std::optional<PointerScrollData> pointer_scroll_data_; |
| |
| // Latest set of pointer scroll data to compute fling scroll. |
| // Front is newer, and back is older. |
| std::deque<PointerScrollData> pointer_scroll_data_set_; |
| |
| // Time of the last pointer frame event. |
| base::TimeTicks last_pointer_frame_time_; |
| |
| // Order set of touch events to be dispatching on the next |
| // wl_touch::frame event. |
| std::deque<std::unique_ptr<FrameData>> touch_frames_; |
| |
| // Order set of pointer events to be dispatching on the next |
| // wl_pointer::frame event. |
| std::deque<std::unique_ptr<FrameData>> pointer_frames_; |
| |
| // Status of fling. |
| bool is_fling_active_ = false; |
| |
| // Map that keeps track of the current touch points, associating touch IDs to |
| // to the surface/location where they happened. |
| struct TouchPoint; |
| base::flat_map<PointerId, std::unique_ptr<TouchPoint>> touch_points_; |
| |
| // The window that currently has tablet tool focus. |
| base::WeakPtr<WaylandWindow> tablet_tool_focused_window_; |
| |
| // Last known tablet tool location. |
| gfx::PointF tablet_tool_location_; |
| |
| // Bitmask of EventFlags used to keep track of the the tablet tool state. |
| int tablet_tool_buttons_ = 0; |
| |
| std::unique_ptr<WaylandEventWatcher> event_watcher_; |
| }; |
| |
| } // namespace ui |
| #endif // UI_OZONE_PLATFORM_WAYLAND_HOST_WAYLAND_EVENT_SOURCE_H_ |