diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 476cee8211866..43257d25cbf1e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -45151,6 +45151,9 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_texture_private.h + ../../../fl ORIGIN: ../../../flutter/shell/platform/linux/fl_texture_registrar.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_texture_registrar_private.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_texture_registrar_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_touch_manager.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_touch_manager.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_touch_manager_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_value.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_value_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_view.cc + ../../../flutter/LICENSE @@ -48111,6 +48114,9 @@ FILE: ../../../flutter/shell/platform/linux/fl_texture_private.h FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar.cc FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar_private.h FILE: ../../../flutter/shell/platform/linux/fl_texture_registrar_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_touch_manager.cc +FILE: ../../../flutter/shell/platform/linux/fl_touch_manager.h +FILE: ../../../flutter/shell/platform/linux/fl_touch_manager_test.cc FILE: ../../../flutter/shell/platform/linux/fl_value.cc FILE: ../../../flutter/shell/platform/linux/fl_value_test.cc FILE: ../../../flutter/shell/platform/linux/fl_view.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index b71b0c74f2479..94c90ad6a219a 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -157,6 +157,7 @@ source_set("flutter_linux_sources") { "fl_texture.cc", "fl_texture_gl.cc", "fl_texture_registrar.cc", + "fl_touch_manager.cc", "fl_value.cc", "fl_view.cc", "fl_view_accessible.cc", @@ -245,6 +246,7 @@ executable("flutter_linux_unittests") { "fl_text_input_handler_test.cc", "fl_texture_gl_test.cc", "fl_texture_registrar_test.cc", + "fl_touch_manager_test.cc", "fl_value_test.cc", "fl_view_accessible_test.cc", "fl_view_test.cc", diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 0cc9497102e37..2ca7f2d867922 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -933,6 +933,136 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, self->embedder_api.SendPointerEvent(self->engine, &fl_event, 1); } +void fl_engine_send_touch_up_event(FlEngine* self, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device) { + g_return_if_fail(FL_IS_ENGINE(self)); + + if (self->engine == nullptr) { + return; + } + + FlutterPointerEvent event; + event.timestamp = timestamp; + event.x = x; + event.y = y; + event.device_kind = kFlutterPointerDeviceKindTouch; + event.device = device; + event.buttons = 0; + event.view_id = view_id; + event.phase = FlutterPointerPhase::kUp; + event.struct_size = sizeof(event); + + self->embedder_api.SendPointerEvent(self->engine, &event, 1); +} + +void fl_engine_send_touch_down_event(FlEngine* self, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device) { + g_return_if_fail(FL_IS_ENGINE(self)); + + if (self->engine == nullptr) { + return; + } + + FlutterPointerEvent event; + event.timestamp = timestamp; + event.x = x; + event.y = y; + event.device_kind = kFlutterPointerDeviceKindTouch; + event.device = device; + event.buttons = FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary; + event.view_id = view_id; + event.phase = FlutterPointerPhase::kDown; + event.struct_size = sizeof(event); + + self->embedder_api.SendPointerEvent(self->engine, &event, 1); +} + +void fl_engine_send_touch_move_event(FlEngine* self, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device) { + g_return_if_fail(FL_IS_ENGINE(self)); + + if (self->engine == nullptr) { + return; + } + + FlutterPointerEvent event; + event.timestamp = timestamp; + event.x = x; + event.y = y; + event.device_kind = kFlutterPointerDeviceKindTouch; + event.device = device; + event.buttons = FlutterPointerMouseButtons::kFlutterPointerButtonMousePrimary; + event.view_id = view_id; + event.phase = FlutterPointerPhase::kMove; + event.struct_size = sizeof(event); + + self->embedder_api.SendPointerEvent(self->engine, &event, 1); +} + +void fl_engine_send_touch_add_event(FlEngine* self, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device) { + g_return_if_fail(FL_IS_ENGINE(self)); + + if (self->engine == nullptr) { + return; + } + + FlutterPointerEvent event; + event.timestamp = timestamp; + event.x = x; + event.y = y; + event.device_kind = kFlutterPointerDeviceKindTouch; + event.device = device; + event.buttons = 0; + event.view_id = view_id; + event.phase = FlutterPointerPhase::kAdd; + event.struct_size = sizeof(event); + + self->embedder_api.SendPointerEvent(self->engine, &event, 1); +} + +void fl_engine_send_touch_remove_event(FlEngine* self, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device) { + g_return_if_fail(FL_IS_ENGINE(self)); + + if (self->engine == nullptr) { + return; + } + + FlutterPointerEvent event; + event.timestamp = timestamp; + event.x = x; + event.y = y; + event.device_kind = kFlutterPointerDeviceKindTouch; + event.device = device; + event.buttons = 0; + event.view_id = view_id; + event.phase = FlutterPointerPhase::kRemove; + event.struct_size = sizeof(event); + + self->embedder_api.SendPointerEvent(self->engine, &event, 1); +} + void fl_engine_send_pointer_pan_zoom_event(FlEngine* self, FlutterViewId view_id, size_t timestamp, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index b6fce3056d9e7..df5694188d472 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -252,6 +252,95 @@ void fl_engine_send_mouse_pointer_event(FlEngine* engine, double scroll_delta_y, int64_t buttons); +/** + * fl_engine_send_touch_up_event: + * @engine: an #FlEngine. + * @view_id: the view that the event occured on. + * @timestamp: time when event occurred in microseconds. + * @x: x location of mouse cursor. + * @y: y location of mouse cursor. + * @device: device id. + * + * Sends a touch up event to the engine. + */ +void fl_engine_send_touch_up_event(FlEngine* engine, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device); + +/** + * fl_engine_send_touch_down_event: + * @engine: an #FlEngine. + * @view_id: the view that the event occured on. + * @timestamp: time when event occurred in microseconds. + * @x: x location of mouse cursor. + * @y: y location of mouse cursor. + * @device: device id. + * + * Sends a touch down event to the engine. + */ +void fl_engine_send_touch_down_event(FlEngine* engine, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device); +/** + * fl_engine_send_touch_move_event: + * @engine: an #FlEngine. + * @view_id: the view that the event occured on. + * @timestamp: time when event occurred in microseconds. + * @x: x location of mouse cursor. + * @y: y location of mouse cursor. + * @device: device id. + * + * Sends a touch move event to the engine. + */ +void fl_engine_send_touch_move_event(FlEngine* engine, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device); + +/** + * fl_engine_send_touch_add_event: + * @engine: an #FlEngine. + * @view_id: the view that the event occured on. + * @timestamp: time when event occurred in microseconds. + * @x: x location of mouse cursor. + * @y: y location of mouse cursor. + * @device: device id. + * + * Sends a touch add event to the engine. + */ +void fl_engine_send_touch_add_event(FlEngine* engine, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device); + +/** + * fl_engine_send_touch_remove_event: + * @engine: an #FlEngine. + * @view_id: the view that the event occured on. + * @timestamp: time when event occurred in microseconds. + * @x: x location of mouse cursor. + * @y: y location of mouse cursor. + * @device: device id. + * + * Sends a touch remove event to the engine. + */ +void fl_engine_send_touch_remove_event(FlEngine* engine, + FlutterViewId view_id, + size_t timestamp, + double x, + double y, + int32_t device); + /** * fl_engine_send_pointer_pan_zoom_event: * @engine: an #FlEngine. diff --git a/shell/platform/linux/fl_touch_manager.cc b/shell/platform/linux/fl_touch_manager.cc new file mode 100644 index 0000000000000..eca5576c2a863 --- /dev/null +++ b/shell/platform/linux/fl_touch_manager.cc @@ -0,0 +1,190 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_touch_manager.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" + +static constexpr int kMicrosecondsPerMillisecond = 1000; +static const int kMinTouchDeviceId = 0; +static const int kMaxTouchDeviceId = 128; + +struct _FlTouchManager { + GObject parent_instance; + + GWeakRef engine; + + FlutterViewId view_id; + + // List of touch device IDs that have been added to the engine. + GList* added_touch_devices; + + GHashTable* number_to_id; + + // Minimum touch device ID that can be used. + guint min_touch_device_id; +}; + +G_DEFINE_TYPE(FlTouchManager, fl_touch_manager, G_TYPE_OBJECT); + +static void fl_touch_manager_dispose(GObject* object) { + FlTouchManager* self = FL_TOUCH_MANAGER(object); + + g_weak_ref_clear(&self->engine); + + g_list_free(self->added_touch_devices); + + g_clear_pointer(&self->number_to_id, g_hash_table_unref); + + G_OBJECT_CLASS(fl_touch_manager_parent_class)->dispose(object); +} + +static void fl_touch_manager_class_init(FlTouchManagerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_touch_manager_dispose; +} + +static void fl_touch_manager_init(FlTouchManager* self) {} + +FlTouchManager* fl_touch_manager_new(FlEngine* engine, FlutterViewId view_id) { + g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr); + + FlTouchManager* self = + FL_TOUCH_MANAGER(g_object_new(fl_touch_manager_get_type(), nullptr)); + + g_weak_ref_init(&self->engine, engine); + self->view_id = view_id; + + self->number_to_id = + g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, nullptr); + + self->min_touch_device_id = kMinTouchDeviceId; + + return self; +} + +// Ensures that a touch add event is sent for the given device. +static void ensure_touch_added(_FlTouchManager* self, + guint event_time, + gdouble x, + gdouble y, + int32_t touch_id, + int32_t device_id) { + // Check if we need to send a touch add event. + if (g_list_find(self->added_touch_devices, GINT_TO_POINTER(touch_id)) != + nullptr) { + return; + } + + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { + return; + } + + fl_engine_send_touch_add_event(engine, self->view_id, + event_time * kMicrosecondsPerMillisecond, x, y, + device_id); + + self->added_touch_devices = + g_list_append(self->added_touch_devices, GINT_TO_POINTER(touch_id)); +} + +// Generates a unique ID to represent |number|. The generated ID is the +// smallest available ID greater than or equal to the minimum touch device ID. +static uint32_t get_generated_id(_FlTouchManager* self, uint32_t number) { + gpointer value; + if (g_hash_table_lookup_extended(self->number_to_id, GUINT_TO_POINTER(number), + nullptr, &value)) { + uint32_t id; + if (value == nullptr) { + id = 0; + } else { + id = GPOINTER_TO_UINT(value); + } + return id; + } + auto values = g_hash_table_get_values(self->number_to_id); + while (values != nullptr && + g_list_find(values, GUINT_TO_POINTER(self->min_touch_device_id)) != + nullptr && + self->min_touch_device_id < kMaxTouchDeviceId) { + ++self->min_touch_device_id; + } + if (self->min_touch_device_id >= kMaxTouchDeviceId) { + self->min_touch_device_id = kMinTouchDeviceId; + } + + g_hash_table_insert(self->number_to_id, GUINT_TO_POINTER(number), + GUINT_TO_POINTER(self->min_touch_device_id)); + return self->min_touch_device_id; +} + +static void release_number(_FlTouchManager* self, uint32_t number) { + if (g_hash_table_contains(self->number_to_id, GINT_TO_POINTER(number))) { + auto id = g_hash_table_lookup(self->number_to_id, GINT_TO_POINTER(number)); + if (GPOINTER_TO_UINT(id) < self->min_touch_device_id) { + self->min_touch_device_id = GPOINTER_TO_UINT(id); + } + g_hash_table_remove(self->number_to_id, GINT_TO_POINTER(number)); + } +} + +void fl_touch_manager_handle_touch_event(FlTouchManager* self, + GdkEventTouch* touch_event, + gint scale_factor) { + g_return_if_fail(FL_IS_TOUCH_MANAGER(self)); + + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { + return; + } + + GdkEvent* event = reinterpret_cast(touch_event); + // get sequence id from GdkEvent + GdkEventSequence* seq = gdk_event_get_event_sequence(event); + // cast pointer to int to get unique id + uint32_t id = reinterpret_cast(seq); + // generate touch id from unique id + auto touch_id = get_generated_id(self, id); + // get device id + auto device_id = + static_cast(kFlutterPointerDeviceKindTouch) << 28 | touch_id; + + gdouble event_x = 0.0, event_y = 0.0; + gdk_event_get_coords(event, &event_x, &event_y); + + double x = event_x * scale_factor; + double y = event_y * scale_factor; + + guint event_time = gdk_event_get_time(event); + + ensure_touch_added(self, event_time, x, y, touch_id, device_id); + + GdkEventType touch_event_type = gdk_event_get_event_type(event); + + switch (touch_event_type) { + case GDK_TOUCH_BEGIN: + fl_engine_send_touch_down_event(engine, self->view_id, + event_time * kMicrosecondsPerMillisecond, + x, y, device_id); + break; + case GDK_TOUCH_UPDATE: + fl_engine_send_touch_move_event(engine, self->view_id, + event_time * kMicrosecondsPerMillisecond, + x, y, device_id); + break; + case GDK_TOUCH_END: + fl_engine_send_touch_up_event(engine, self->view_id, + event_time * kMicrosecondsPerMillisecond, x, + y, device_id); + + fl_engine_send_touch_remove_event( + engine, self->view_id, event_time * kMicrosecondsPerMillisecond, x, y, + device_id); + release_number(self, id); + self->added_touch_devices = + g_list_remove(self->added_touch_devices, GINT_TO_POINTER(touch_id)); + break; + default: + break; + } +} diff --git a/shell/platform/linux/fl_touch_manager.h b/shell/platform/linux/fl_touch_manager.h new file mode 100644 index 0000000000000..d79e1772675d6 --- /dev/null +++ b/shell/platform/linux/fl_touch_manager.h @@ -0,0 +1,44 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_TOUCH_MANAGER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_TOUCH_MANAGER_H_ + +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlTouchManager, + fl_touch_manager, + FL, + TOUCH_MANAGER, + GObject); + +/** + * fl_touch_manager_new: + * @engine: an #FlEngine. + * @view_id: the view being managed. + * + * Create a new #FlTouchManager. + * + * Returns: a new #FlTouchManager. + */ +FlTouchManager* fl_touch_manager_new(FlEngine* engine, FlutterViewId view_id); + +/** + * fl_touch_manager_handle_touch_event: + * @manager: an #FlTouchManager. + * @event: the touch event. + * @scale_factor: the GTK scaling factor of the window. + */ +void fl_touch_manager_handle_touch_event(FlTouchManager* manager, + GdkEventTouch* event, + gint scale_factor); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TOUCH_MANAGER_H_ diff --git a/shell/platform/linux/fl_touch_manager_test.cc b/shell/platform/linux/fl_touch_manager_test.cc new file mode 100644 index 0000000000000..90d1d4621a92a --- /dev/null +++ b/shell/platform/linux/fl_touch_manager_test.cc @@ -0,0 +1,103 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_touch_manager.h" +#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" + +#include +#include + +#include "gtest/gtest.h" + +static void log_pointer_events( + FlEngine* engine, + std::vector& pointer_events) { + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + embedder_api->SendPointerEvent = MOCK_ENGINE_PROC( + SendPointerEvent, + ([&pointer_events](auto engine, const FlutterPointerEvent* events, + size_t events_count) { + for (size_t i = 0; i < events_count; i++) { + pointer_events.push_back(events[i]); + } + + return kSuccess; + })); +} + +struct _FakeGdkDevice { + GObject parent_instance; + gchar* name; + GdkInputSource source; +}; +static GdkDevice* makeFakeDevice(GdkInputSource source) { + _FakeGdkDevice* device = + static_cast<_FakeGdkDevice*>(g_malloc0(sizeof(_FakeGdkDevice))); + device->source = source; + // Bully the type checker + (reinterpret_cast(device))->g_class = + static_cast(g_malloc0(sizeof(GTypeClass))); + (reinterpret_cast(device))->g_class->g_type = GDK_TYPE_DEVICE; + return reinterpret_cast(device); +} + +TEST(FlTouchManagerTest, TouchEvents) { + g_autoptr(FlEngine) engine = make_mock_engine(); + std::vector pointer_events; + log_pointer_events(engine, pointer_events); + + g_autoptr(FlTouchManager) manager = fl_touch_manager_new(engine, 0); + + GdkDevice* touchscreen = makeFakeDevice(GDK_SOURCE_TOUCHSCREEN); + GdkEventTouch* event = + reinterpret_cast(gdk_event_new(GDK_TOUCH_BEGIN)); + event->time = 1; + event->x = 4.0; + event->y = 8.0; + event->device = touchscreen; + fl_touch_manager_handle_touch_event(manager, event, 1.0); + EXPECT_EQ(pointer_events.size(), 2u); + EXPECT_EQ(pointer_events[0].x, 4.0); + EXPECT_EQ(pointer_events[0].y, 8.0); + EXPECT_EQ(pointer_events[0].device_kind, kFlutterPointerDeviceKindTouch); + EXPECT_EQ(pointer_events[0].timestamp, + 1000lu); // Milliseconds -> Microseconds + EXPECT_EQ(pointer_events[0].phase, kAdd); + + EXPECT_EQ(pointer_events[1].x, 4.0); + EXPECT_EQ(pointer_events[1].y, 8.0); + EXPECT_EQ(pointer_events[1].device_kind, kFlutterPointerDeviceKindTouch); + EXPECT_EQ(pointer_events[1].timestamp, + 1000lu); // Milliseconds -> Microseconds + EXPECT_EQ(pointer_events[1].phase, kDown); + + event->type = GDK_TOUCH_UPDATE; + fl_touch_manager_handle_touch_event(manager, event, 1.0); + EXPECT_EQ(pointer_events.size(), 3u); + EXPECT_EQ(pointer_events[2].x, 4.0); + EXPECT_EQ(pointer_events[2].y, 8.0); + EXPECT_EQ(pointer_events[2].device_kind, kFlutterPointerDeviceKindTouch); + EXPECT_EQ(pointer_events[2].timestamp, + 1000lu); // Milliseconds -> Microseconds + EXPECT_EQ(pointer_events[2].phase, kMove); + + event->type = GDK_TOUCH_END; + fl_touch_manager_handle_touch_event(manager, event, 1.0); + EXPECT_EQ(pointer_events.size(), 5u); + EXPECT_EQ(pointer_events[3].x, 4.0); + EXPECT_EQ(pointer_events[3].y, 8.0); + EXPECT_EQ(pointer_events[3].device_kind, kFlutterPointerDeviceKindTouch); + EXPECT_EQ(pointer_events[3].timestamp, + 1000lu); // Milliseconds -> Microseconds + EXPECT_EQ(pointer_events[3].phase, kUp); + + EXPECT_EQ(pointer_events[4].x, 4.0); + EXPECT_EQ(pointer_events[4].y, 8.0); + EXPECT_EQ(pointer_events[4].device_kind, kFlutterPointerDeviceKindTouch); + EXPECT_EQ(pointer_events[4].timestamp, + 1000lu); // Milliseconds -> Microseconds + EXPECT_EQ(pointer_events[4].phase, kRemove); +} \ No newline at end of file diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index be8cdd7f2051a..49a1ec65f1089 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -23,6 +23,7 @@ #include "flutter/shell/platform/linux/fl_socket_accessible.h" #include "flutter/shell/platform/linux/fl_text_input_handler.h" #include "flutter/shell/platform/linux/fl_text_input_view_delegate.h" +#include "flutter/shell/platform/linux/fl_touch_manager.h" #include "flutter/shell/platform/linux/fl_view_accessible.h" #include "flutter/shell/platform/linux/fl_window_state_monitor.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" @@ -61,6 +62,9 @@ struct _FlView { // Manages pointer events. FlPointerManager* pointer_manager; + // Manages touch events. + FlTouchManager* touch_manager; + // Manages keyboard events. FlKeyboardManager* keyboard_manager; @@ -147,6 +151,11 @@ static void init_scrolling(FlView* self) { fl_scrolling_manager_new(self->engine, self->view_id); } +static void init_touch(FlView* self) { + g_clear_object(&self->touch_manager); + self->touch_manager = fl_touch_manager_new(self->engine, self->view_id); +} + static FlutterPointerDeviceKind get_device_kind(GdkEvent* event) { GdkDevice* device = gdk_event_get_source_device(event); GdkInputSource source = gdk_device_get_source(device); @@ -266,6 +275,7 @@ static void update_semantics_cb(FlEngine* engine, static void on_pre_engine_restart_cb(FlView* self) { init_keyboard(self); init_scrolling(self); + init_touch(self); } // Implements FlRenderable::redraw @@ -407,12 +417,26 @@ static gboolean scroll_event_cb(FlView* self, GdkEventScroll* event) { return TRUE; } +static gboolean touch_event_cb(FlView* self, GdkEventTouch* event) { + fl_touch_manager_handle_touch_event( + self->touch_manager, event, + gtk_widget_get_scale_factor(GTK_WIDGET(self))); + return TRUE; +} + // Signal handler for GtkWidget::motion-notify-event static gboolean motion_notify_event_cb(FlView* self, GdkEventMotion* motion_event) { GdkEvent* event = reinterpret_cast(motion_event); sync_modifier_if_needed(self, event); + // return if touch event + auto event_type = gdk_event_get_event_type(event); + if (event_type == GDK_TOUCH_BEGIN || event_type == GDK_TOUCH_UPDATE || + event_type == GDK_TOUCH_END || event_type == GDK_TOUCH_CANCEL) { + return FALSE; + } + gdouble x = 0.0, y = 0.0; gdk_event_get_coords(event, &x, &y); gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); @@ -481,6 +505,7 @@ static GdkGLContext* create_context_cb(FlView* self) { gtk_widget_get_parent_window(GTK_WIDGET(self))); init_scrolling(self); + init_touch(self); g_autoptr(GError) error = nullptr; if (!fl_renderer_gdk_create_contexts(self->renderer, &error)) { @@ -616,6 +641,7 @@ static void fl_view_dispose(GObject* object) { g_clear_object(&self->window_state_monitor); g_clear_object(&self->scrolling_manager); g_clear_object(&self->pointer_manager); + g_clear_object(&self->touch_manager); g_clear_object(&self->keyboard_manager); g_clear_object(&self->keyboard_handler); g_clear_object(&self->view_accessible); @@ -692,7 +718,7 @@ static void fl_view_init(FlView* self) { gtk_widget_add_events(event_box, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | - GDK_SMOOTH_SCROLL_MASK); + GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK); g_signal_connect_swapped(event_box, "button-press-event", G_CALLBACK(button_press_event_cb), self); @@ -719,6 +745,8 @@ static void fl_view_init(FlView* self) { G_CALLBACK(gesture_rotation_update_cb), self); g_signal_connect_swapped(rotate, "end", G_CALLBACK(gesture_rotation_end_cb), self); + g_signal_connect_swapped(event_box, "touch-event", G_CALLBACK(touch_event_cb), + self); self->gl_area = GTK_GL_AREA(gtk_gl_area_new()); gtk_gl_area_set_has_alpha(self->gl_area, TRUE);