diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index d6c08d3aacf..6ca91892db0 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -410,6 +410,8 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, size_t timestamp, double x, double y, + double scroll_delta_x, + double scroll_delta_y, int64_t buttons) { g_return_if_fail(FL_IS_ENGINE(self)); @@ -422,6 +424,10 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, fl_event.timestamp = timestamp; fl_event.x = x; fl_event.y = y; + if (scroll_delta_x != 0 || scroll_delta_y != 0) + fl_event.signal_kind = kFlutterPointerSignalKindScroll; + fl_event.scroll_delta_x = scroll_delta_x; + fl_event.scroll_delta_y = scroll_delta_y; fl_event.device_kind = kFlutterPointerDeviceKindMouse; fl_event.buttons = buttons; FlutterEngineSendPointerEvent(self->engine, &fl_event, 1); diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 0d5216f1662..6c912979ba1 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -108,6 +108,8 @@ void fl_engine_send_window_metrics_event(FlEngine* engine, * @timestamp: time when event occurred in microseconds. * @x: x location of mouse cursor. * @y: y location of mouse cursor. + * @scroll_delta_x: x offset of scroll. + * @scroll_delta_y: y offset of scroll. * @buttons: buttons that are pressed. * * Sends a mouse pointer event to the engine. @@ -117,6 +119,8 @@ void fl_engine_send_mouse_pointer_event(FlEngine* engine, size_t timestamp, double x, double y, + double scroll_delta_x, + double scroll_delta_y, int64_t buttons); /** diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index a57d1204aa7..6cdd74ac425 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -89,7 +89,9 @@ static gboolean fl_view_send_pointer_button_event(FlView* self, gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); fl_engine_send_mouse_pointer_event( self->engine, phase, event->time * kMicrosecondsPerMillisecond, - event->x * scale_factor, event->y * scale_factor, self->button_state); + event->x * scale_factor, event->y * scale_factor, 0, 0, + self->button_state); + return TRUE; } @@ -206,7 +208,8 @@ static void fl_view_realize(GtkWidget* widget) { window_attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK; + GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK; gint window_attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; @@ -261,6 +264,43 @@ static gboolean fl_view_button_release_event(GtkWidget* widget, return fl_view_send_pointer_button_event(self, event); } +// Implements GtkWidget::scroll_event. +static gboolean fl_view_scroll_event(GtkWidget* widget, GdkEventScroll* event) { + FlView* self = FL_VIEW(widget); + + // TODO(robert-ancell): Update to use GtkEventControllerScroll when we can + // depend on GTK 3.24. + + gdouble scroll_delta_x = 0.0, scroll_delta_y = 0.0; + if (event->direction == GDK_SCROLL_SMOOTH) { + scroll_delta_x = event->delta_x; + scroll_delta_y = event->delta_y; + } else if (event->direction == GDK_SCROLL_UP) { + scroll_delta_y = -1; + } else if (event->direction == GDK_SCROLL_DOWN) { + scroll_delta_y = 1; + } else if (event->direction == GDK_SCROLL_LEFT) { + scroll_delta_x = -1; + } else if (event->direction == GDK_SCROLL_RIGHT) { + scroll_delta_x = 1; + } + + // TODO: See if this can be queried from the OS; this value is chosen + // arbitrarily to get something that feels reasonable. + const int kScrollOffsetMultiplier = 20; + scroll_delta_x *= kScrollOffsetMultiplier; + scroll_delta_y *= kScrollOffsetMultiplier; + + gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); + fl_engine_send_mouse_pointer_event( + self->engine, self->button_state != 0 ? kMove : kHover, + event->time * kMicrosecondsPerMillisecond, event->x * scale_factor, + event->y * scale_factor, scroll_delta_x, scroll_delta_y, + self->button_state); + + return TRUE; +} + // Implements GtkWidget::motion_notify_event. static gboolean fl_view_motion_notify_event(GtkWidget* widget, GdkEventMotion* event) { @@ -273,7 +313,7 @@ static gboolean fl_view_motion_notify_event(GtkWidget* widget, fl_engine_send_mouse_pointer_event( self->engine, self->button_state != 0 ? kMove : kHover, event->time * kMicrosecondsPerMillisecond, event->x * scale_factor, - event->y * scale_factor, self->button_state); + event->y * scale_factor, 0, 0, self->button_state); return TRUE; } @@ -313,6 +353,7 @@ static void fl_view_class_init(FlViewClass* klass) { GTK_WIDGET_CLASS(klass)->size_allocate = fl_view_size_allocate; GTK_WIDGET_CLASS(klass)->button_press_event = fl_view_button_press_event; GTK_WIDGET_CLASS(klass)->button_release_event = fl_view_button_release_event; + GTK_WIDGET_CLASS(klass)->scroll_event = fl_view_scroll_event; GTK_WIDGET_CLASS(klass)->motion_notify_event = fl_view_motion_notify_event; GTK_WIDGET_CLASS(klass)->key_press_event = fl_view_key_press_event; GTK_WIDGET_CLASS(klass)->key_release_event = fl_view_key_release_event;