Provide monitor information. (#161359) Fixes https://github.com/flutter/flutter/issues/144230
diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 45adea5..9fa0987 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter
@@ -44348,6 +44348,9 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project_private.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_display_monitor.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_display_monitor.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_display_monitor_test.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_engine.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_engine_private.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_engine_test.cc + ../../../flutter/LICENSE @@ -47317,6 +47320,9 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc FILE: ../../../flutter/shell/platform/linux/fl_dart_project_private.h FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_display_monitor.cc +FILE: ../../../flutter/shell/platform/linux/fl_display_monitor.h +FILE: ../../../flutter/shell/platform/linux/fl_display_monitor_test.cc FILE: ../../../flutter/shell/platform/linux/fl_engine.cc FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h FILE: ../../../flutter/shell/platform/linux/fl_engine_test.cc
diff --git a/engine/src/flutter/shell/platform/linux/BUILD.gn b/engine/src/flutter/shell/platform/linux/BUILD.gn index 94c90ad..ba44674 100644 --- a/engine/src/flutter/shell/platform/linux/BUILD.gn +++ b/engine/src/flutter/shell/platform/linux/BUILD.gn
@@ -107,6 +107,7 @@ "fl_binary_codec.cc", "fl_binary_messenger.cc", "fl_dart_project.cc", + "fl_display_monitor.cc", "fl_engine.cc", "fl_event_channel.cc", "fl_framebuffer.cc", @@ -216,6 +217,7 @@ "fl_binary_codec_test.cc", "fl_binary_messenger_test.cc", "fl_dart_project_test.cc", + "fl_display_monitor_test.cc", "fl_engine_test.cc", "fl_event_channel_test.cc", "fl_framebuffer_test.cc",
diff --git a/engine/src/flutter/shell/platform/linux/fl_display_monitor.cc b/engine/src/flutter/shell/platform/linux/fl_display_monitor.cc new file mode 100644 index 0000000..bea40b2 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_display_monitor.cc
@@ -0,0 +1,120 @@ +// 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_display_monitor.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" + +struct _FlDisplayMonitor { + GObject parent_instance; + + // Engine being updated. + GWeakRef engine; + + // Display being monitored. + GdkDisplay* display; + + // Mapping of GdkMonitor to display IDs. + GHashTable* display_ids_by_monitor; + + // Next ID to assign to a new monitor. + FlutterEngineDisplayId next_display_id; +}; + +G_DEFINE_TYPE(FlDisplayMonitor, fl_display_monitor, G_TYPE_OBJECT) + +// Send the current monitor state to the engine. +static void notify_display_update(FlDisplayMonitor* self) { + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { + return; + } + + int n_monitors = gdk_display_get_n_monitors(self->display); + g_autofree FlutterEngineDisplay* displays = + g_new0(FlutterEngineDisplay, n_monitors); + for (int i = 0; i < n_monitors; i++) { + FlutterEngineDisplay* display = &displays[i]; + + GdkMonitor* monitor = gdk_display_get_monitor(self->display, i); + FlutterEngineDisplayId display_id = GPOINTER_TO_INT( + g_hash_table_lookup(self->display_ids_by_monitor, monitor)); + if (display_id == 0) { + display_id = self->next_display_id; + g_hash_table_insert(self->display_ids_by_monitor, g_object_ref(monitor), + GINT_TO_POINTER(display_id)); + self->next_display_id++; + } + + GdkRectangle geometry; + gdk_monitor_get_geometry(monitor, &geometry); + + display->struct_size = sizeof(FlutterEngineDisplay); + display->display_id = display_id; + display->single_display = false; + display->refresh_rate = gdk_monitor_get_refresh_rate(monitor) / 1000.0; + display->width = geometry.width; + display->height = geometry.height; + display->device_pixel_ratio = gdk_monitor_get_scale_factor(monitor); + } + + fl_engine_notify_display_update(engine, displays, n_monitors); +} + +static void monitor_added_cb(FlDisplayMonitor* self, GdkMonitor* monitor) { + notify_display_update(self); +} + +static void monitor_removed_cb(FlDisplayMonitor* self, GdkMonitor* monitor) { + g_hash_table_remove(self->display_ids_by_monitor, monitor); + notify_display_update(self); +} + +static void fl_display_monitor_dispose(GObject* object) { + FlDisplayMonitor* self = FL_DISPLAY_MONITOR(object); + + g_weak_ref_clear(&self->engine); + g_clear_object(&self->display); + g_clear_pointer(&self->display_ids_by_monitor, g_hash_table_unref); + + G_OBJECT_CLASS(fl_display_monitor_parent_class)->dispose(object); +} + +static void fl_display_monitor_class_init(FlDisplayMonitorClass* klass) { + GObjectClass* object_class = G_OBJECT_CLASS(klass); + object_class->dispose = fl_display_monitor_dispose; +} + +static void fl_display_monitor_init(FlDisplayMonitor* self) { + self->display_ids_by_monitor = g_hash_table_new_full( + g_direct_hash, g_direct_equal, g_object_unref, nullptr); + self->next_display_id = 1; +} + +FlDisplayMonitor* fl_display_monitor_new(FlEngine* engine, + GdkDisplay* display) { + FlDisplayMonitor* self = + FL_DISPLAY_MONITOR(g_object_new(fl_display_monitor_get_type(), nullptr)); + g_weak_ref_init(&self->engine, engine); + self->display = GDK_DISPLAY(g_object_ref(display)); + return self; +} + +void fl_display_monitor_start(FlDisplayMonitor* self) { + g_return_if_fail(FL_IS_DISPLAY_MONITOR(self)); + + g_signal_connect_object(self->display, "monitor-added", + G_CALLBACK(monitor_added_cb), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(self->display, "monitor-removed", + G_CALLBACK(monitor_removed_cb), self, + G_CONNECT_SWAPPED); + notify_display_update(self); +} + +FlutterEngineDisplayId fl_display_monitor_get_display_id(FlDisplayMonitor* self, + GdkMonitor* monitor) { + g_return_val_if_fail(FL_IS_DISPLAY_MONITOR(self), 0); + return GPOINTER_TO_INT( + g_hash_table_lookup(self->display_ids_by_monitor, monitor)); +}
diff --git a/engine/src/flutter/shell/platform/linux/fl_display_monitor.h b/engine/src/flutter/shell/platform/linux/fl_display_monitor.h new file mode 100644 index 0000000..5660a96 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_display_monitor.h
@@ -0,0 +1,56 @@ +// 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_DISPLAY_MONITOR_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_DISPLAY_MONITOR_H_ + +#include <gdk/gdk.h> + +#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(FlDisplayMonitor, + fl_display_monitor, + FL, + DISPLAY_MONITOR, + GObject); + +/** + * fl_display_monitor_new: + * @engine: engine to update. + * @display: display to monitor. + * + * Creates a new object to keep the engine updated with the currently used + * displays. In GDK, a display is called a "monitor". + * + * Returns: a new #FlDisplayMontior. + */ +FlDisplayMonitor* fl_display_monitor_new(FlEngine* engine, GdkDisplay* display); + +/** + * fl_display_monitor_start: + * @monitor: an #FlDisplayMonitor. + * + * Start monitoring for display changes. + */ +void fl_display_monitor_start(FlDisplayMonitor* monitor); + +/** + * fl_display_monitor_get_display_id: + * @monitor: an #FlDisplayMonitor. + * @gdk_monitor: GDK monitor to get display ID for. + * + * Get the ID Flutter is using for a given monitor. + * + * Returns: an ID or 0 if unknown. + */ +FlutterEngineDisplayId fl_display_monitor_get_display_id( + FlDisplayMonitor* monitor, + GdkMonitor* gdk_monitor); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_DISPLAY_MONITOR_H_
diff --git a/engine/src/flutter/shell/platform/linux/fl_display_monitor_test.cc b/engine/src/flutter/shell/platform/linux/fl_display_monitor_test.cc new file mode 100644 index 0000000..b21dc73 --- /dev/null +++ b/engine/src/flutter/shell/platform/linux/fl_display_monitor_test.cc
@@ -0,0 +1,36 @@ +// 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_display_monitor.h" +#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" + +#include "gtest/gtest.h" + +TEST(FlDisplayMonitorTest, Test) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + + bool called = false; + fl_engine_get_embedder_api(engine)->NotifyDisplayUpdate = MOCK_ENGINE_PROC( + NotifyDisplayUpdate, + ([&called](auto engine, FlutterEngineDisplaysUpdateType update_type, + const FlutterEngineDisplay* displays, size_t displays_length) { + called = true; + + EXPECT_EQ(displays_length, 1u); + + return kSuccess; + })); + + g_autoptr(FlDisplayMonitor) monitor = + fl_display_monitor_new(engine, gdk_display_get_default()); + EXPECT_FALSE(called); + fl_display_monitor_start(monitor); + EXPECT_TRUE(called); +}
diff --git a/engine/src/flutter/shell/platform/linux/fl_engine.cc b/engine/src/flutter/shell/platform/linux/fl_engine.cc index 1523906..01329cf 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine.cc
@@ -12,6 +12,7 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_dart_project_private.h" +#include "flutter/shell/platform/linux/fl_display_monitor.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h" #include "flutter/shell/platform/linux/fl_platform_handler.h" @@ -41,6 +42,9 @@ // The project this engine is running. FlDartProject* project; + // Watches for monitors changes to update engine. + FlDisplayMonitor* display_monitor; + // Renders the Flutter app. FlRenderer* renderer; @@ -532,6 +536,11 @@ return self->renderer; } +FlDisplayMonitor* fl_engine_get_display_monitor(FlEngine* self) { + g_return_val_if_fail(FL_IS_ENGINE(self), nullptr); + return self->display_monitor; +} + gboolean fl_engine_start(FlEngine* self, GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); @@ -642,23 +651,9 @@ g_warning("Failed to enable accessibility features on Flutter engine"); } - gdouble refresh_rate = fl_renderer_get_refresh_rate(self->renderer); - // FlutterEngineDisplay::refresh_rate expects 0 if the refresh rate is - // unknown. - if (refresh_rate <= 0.0) { - refresh_rate = 0.0; - } - FlutterEngineDisplay display = {}; - display.struct_size = sizeof(FlutterEngineDisplay); - display.display_id = 0; - display.single_display = true; - display.refresh_rate = refresh_rate; - - result = self->embedder_api.NotifyDisplayUpdate( - self->engine, kFlutterEngineDisplaysUpdateTypeStartup, &display, 1); - if (result != kSuccess) { - g_warning("Failed to notify display update to Flutter engine: %d", result); - } + self->display_monitor = + fl_display_monitor_new(self, gdk_display_get_default()); + fl_display_monitor_start(self->display_monitor); return TRUE; } @@ -667,6 +662,19 @@ return &(self->embedder_api); } +void fl_engine_notify_display_update(FlEngine* self, + const FlutterEngineDisplay* displays, + size_t displays_length) { + g_return_if_fail(FL_IS_ENGINE(self)); + + FlutterEngineResult result = self->embedder_api.NotifyDisplayUpdate( + self->engine, kFlutterEngineDisplaysUpdateTypeStartup, displays, + displays_length); + if (result != kSuccess) { + g_warning("Failed to notify display update to Flutter engine: %d", result); + } +} + FlutterViewId fl_engine_add_view(FlEngine* self, size_t width, size_t height, @@ -681,11 +689,16 @@ FlutterViewId view_id = self->next_view_id; self->next_view_id++; + // We don't know which display this view will open on, so set to zero and this + // will be updated in a following FlutterWindowMetricsEvent + FlutterEngineDisplayId display_id = 0; + FlutterWindowMetricsEvent metrics; metrics.struct_size = sizeof(FlutterWindowMetricsEvent); metrics.width = width; metrics.height = height; metrics.pixel_ratio = pixel_ratio; + metrics.display_id = display_id; metrics.view_id = view_id; FlutterAddViewInfo info; info.struct_size = sizeof(FlutterAddViewInfo); @@ -881,6 +894,7 @@ } void fl_engine_send_window_metrics_event(FlEngine* self, + FlutterEngineDisplayId display_id, FlutterViewId view_id, size_t width, size_t height, @@ -896,6 +910,7 @@ event.width = width; event.height = height; event.pixel_ratio = pixel_ratio; + event.display_id = display_id; event.view_id = view_id; self->embedder_api.SendWindowMetricsEvent(self->engine, &event); }
diff --git a/engine/src/flutter/shell/platform/linux/fl_engine_private.h b/engine/src/flutter/shell/platform/linux/fl_engine_private.h index 96e9b6b..419073a 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine_private.h +++ b/engine/src/flutter/shell/platform/linux/fl_engine_private.h
@@ -8,6 +8,7 @@ #include <glib-object.h> #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/fl_display_monitor.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h" #include "flutter/shell/platform/linux/fl_renderer.h" #include "flutter/shell/platform/linux/fl_task_runner.h" @@ -82,6 +83,16 @@ FlRenderer* fl_engine_get_renderer(FlEngine* engine); /** + * fl_engine_get_display_monitor: + * @engine: an #FlEngine. + * + * Gets the display monitor used by this engine. + * + * Returns: an #FlDisplayMonitor. + */ +FlDisplayMonitor* fl_engine_get_display_monitor(FlEngine* engine); + +/** * fl_engine_start: * @engine: an #FlEngine. * @error: (allow-none): #GError location to store the error occurring, or %NULL @@ -104,6 +115,18 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* engine); /** + * fl_engine_notify_display_update: + * @engine: an #FlEngine. + * @displays: displays present on the system. + * @displays_length: length of @displays. + * + * Notify the current displays that are in the system. + */ +void fl_engine_notify_display_update(FlEngine* engine, + const FlutterEngineDisplay* displays, + size_t displays_length); + +/** * fl_engine_add_view: * @engine: an #FlEngine. * @width: width of view in pixels. @@ -213,6 +236,7 @@ /** * fl_engine_send_window_metrics_event: * @engine: an #FlEngine. + * @display_id: the display this view is rendering on. * @view_id: the view that the event occured on. * @width: width of the window in pixels. * @height: height of the window in pixels. @@ -221,6 +245,7 @@ * Sends a window metrics event to the engine. */ void fl_engine_send_window_metrics_event(FlEngine* engine, + FlutterEngineDisplayId display_id, FlutterViewId view_id, size_t width, size_t height,
diff --git a/engine/src/flutter/shell/platform/linux/fl_engine_test.cc b/engine/src/flutter/shell/platform/linux/fl_engine_test.cc index 9378799..5f183b0 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine_test.cc
@@ -14,6 +14,63 @@ // MOCK_ENGINE_PROC is leaky by design // NOLINTBEGIN(clang-analyzer-core.StackAddressEscape) +// Checks notifying display updates works. +TEST(FlEngineTest, NotifyDisplayUpdate) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + + bool called = false; + fl_engine_get_embedder_api(engine)->NotifyDisplayUpdate = MOCK_ENGINE_PROC( + NotifyDisplayUpdate, + ([&called](auto engine, FlutterEngineDisplaysUpdateType update_type, + const FlutterEngineDisplay* displays, size_t displays_length) { + called = true; + EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup); + EXPECT_EQ(displays_length, 2u); + + EXPECT_EQ(displays[0].display_id, 1u); + EXPECT_EQ(displays[0].refresh_rate, 60); + EXPECT_EQ(displays[0].width, 1024u); + EXPECT_EQ(displays[0].height, 768u); + EXPECT_EQ(displays[0].device_pixel_ratio, 1.0); + + EXPECT_EQ(displays[1].display_id, 2u); + EXPECT_EQ(displays[1].refresh_rate, 120); + EXPECT_EQ(displays[1].width, 3840u); + EXPECT_EQ(displays[1].height, 2160u); + EXPECT_EQ(displays[1].device_pixel_ratio, 2.0); + + return kSuccess; + })); + + FlutterEngineDisplay displays[2] = { + { + .struct_size = sizeof(FlutterEngineDisplay), + .display_id = 1, + .single_display = false, + .refresh_rate = 60.0, + .width = 1024, + .height = 768, + .device_pixel_ratio = 1.0, + }, + { + .struct_size = sizeof(FlutterEngineDisplay), + .display_id = 2, + .single_display = false, + .refresh_rate = 120.0, + .width = 3840, + .height = 2160, + .device_pixel_ratio = 2.0, + }}; + fl_engine_notify_display_update(engine, displays, 2); + + EXPECT_TRUE(called); +} + // Checks sending window metrics events works. TEST(FlEngineTest, WindowMetrics) { g_autoptr(FlDartProject) project = fl_dart_project_new(); @@ -28,6 +85,7 @@ SendWindowMetricsEvent, ([&called](auto engine, const FlutterWindowMetricsEvent* event) { called = true; + EXPECT_EQ(event->display_id, 99u); EXPECT_EQ(event->view_id, 1); EXPECT_EQ(event->width, static_cast<size_t>(3840)); EXPECT_EQ(event->height, static_cast<size_t>(2160)); @@ -36,7 +94,7 @@ return kSuccess; })); - fl_engine_send_window_metrics_event(engine, 1, 3840, 2160, 2.0); + fl_engine_send_window_metrics_event(engine, 99, 1, 3840, 2160, 2.0); EXPECT_TRUE(called); }
diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer.cc b/engine/src/flutter/shell/platform/linux/fl_renderer.cc index 600dab0..2d5d918 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer.cc +++ b/engine/src/flutter/shell/platform/linux/fl_renderer.cc
@@ -381,11 +381,6 @@ FL_RENDERER_GET_CLASS(self)->clear_current(self); } -gdouble fl_renderer_get_refresh_rate(FlRenderer* self) { - g_return_val_if_fail(FL_IS_RENDERER(self), -1.0); - return FL_RENDERER_GET_CLASS(self)->get_refresh_rate(self); -} - guint32 fl_renderer_get_fbo(FlRenderer* self) { g_return_val_if_fail(FL_IS_RENDERER(self), 0);
diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer.h b/engine/src/flutter/shell/platform/linux/fl_renderer.h index b59f5e4..b4b5216 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer.h +++ b/engine/src/flutter/shell/platform/linux/fl_renderer.h
@@ -55,16 +55,6 @@ * @renderer: an #FlRenderer. */ void (*clear_current)(FlRenderer* renderer); - - /** - * Virtual method called when Flutter wants to get the refresh rate of the - * renderer. - * @renderer: an #FlRenderer. - * - * Returns: The refresh rate of the display in Hz. If the refresh rate is - * not available, returns -1.0. - */ - gdouble (*get_refresh_rate)(FlRenderer* renderer); }; /** @@ -235,15 +225,6 @@ */ void fl_renderer_cleanup(FlRenderer* renderer); -/** - * fl_renderer_get_refresh_rate: - * @renderer: an #FlRenderer. - * - * Returns: The refresh rate of the display in Hz. If the refresh rate is - * not available, returns -1.0. - */ -gdouble fl_renderer_get_refresh_rate(FlRenderer* renderer); - G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_RENDERER_H_
diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc b/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc index 2cbb46e..a0bc4e7 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc +++ b/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc
@@ -39,24 +39,6 @@ gdk_gl_context_clear_current(); } -// Implements FlRenderer::get_refresh_rate. -static gdouble fl_renderer_gdk_get_refresh_rate(FlRenderer* renderer) { - FlRendererGdk* self = FL_RENDERER_GDK(renderer); - GdkDisplay* display = gdk_window_get_display(self->window); - GdkMonitor* monitor = - gdk_display_get_monitor_at_window(display, self->window); - if (monitor == nullptr) { - return -1.0; - } - - int refresh_rate = gdk_monitor_get_refresh_rate(monitor); - if (refresh_rate <= 0) { - return -1.0; - } - // the return value is in milli-hertz, convert to hertz - return static_cast<gdouble>(refresh_rate) / 1000.0; -} - static void fl_renderer_gdk_dispose(GObject* object) { FlRendererGdk* self = FL_RENDERER_GDK(object); @@ -74,7 +56,6 @@ FL_RENDERER_CLASS(klass)->make_resource_current = fl_renderer_gdk_make_resource_current; FL_RENDERER_CLASS(klass)->clear_current = fl_renderer_gdk_clear_current; - FL_RENDERER_CLASS(klass)->get_refresh_rate = fl_renderer_gdk_get_refresh_rate; } static void fl_renderer_gdk_init(FlRendererGdk* self) {}
diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer_headless.cc b/engine/src/flutter/shell/platform/linux/fl_renderer_headless.cc index c94cd1f..1736e14 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer_headless.cc +++ b/engine/src/flutter/shell/platform/linux/fl_renderer_headless.cc
@@ -19,18 +19,11 @@ // Implements FlRenderer::clear_current. static void fl_renderer_headless_clear_current(FlRenderer* renderer) {} -// Implements FlRenderer::get_refresh_rate. -static gdouble fl_renderer_headless_get_refresh_rate(FlRenderer* renderer) { - return -1.0; -} - static void fl_renderer_headless_class_init(FlRendererHeadlessClass* klass) { FL_RENDERER_CLASS(klass)->make_current = fl_renderer_headless_make_current; FL_RENDERER_CLASS(klass)->make_resource_current = fl_renderer_headless_make_resource_current; FL_RENDERER_CLASS(klass)->clear_current = fl_renderer_headless_clear_current; - FL_RENDERER_CLASS(klass)->get_refresh_rate = - fl_renderer_headless_get_refresh_rate; } static void fl_renderer_headless_init(FlRendererHeadless* self) {}
diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer_test.cc b/engine/src/flutter/shell/platform/linux/fl_renderer_test.cc index c5d2346..0c808fb 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_renderer_test.cc
@@ -93,20 +93,6 @@ EXPECT_EQ(texture_2d_binding, kFakeTextureName); } -static constexpr double kExpectedRefreshRate = 120.0; -static gdouble renderer_get_refresh_rate(FlRenderer* renderer) { - return kExpectedRefreshRate; -} - -TEST(FlRendererTest, RefreshRate) { - g_autoptr(FlMockRenderer) renderer = - fl_mock_renderer_new(&renderer_get_refresh_rate); - - gdouble result_refresh_rate = - fl_renderer_get_refresh_rate(FL_RENDERER(renderer)); - EXPECT_DOUBLE_EQ(result_refresh_rate, kExpectedRefreshRate); -} - TEST(FlRendererTest, BlitFramebuffer) { ::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;
diff --git a/engine/src/flutter/shell/platform/linux/fl_view.cc b/engine/src/flutter/shell/platform/linux/fl_view.cc index 49a1ec6..7b5f87b 100644 --- a/engine/src/flutter/shell/platform/linux/fl_view.cc +++ b/engine/src/flutter/shell/platform/linux/fl_view.cc
@@ -221,8 +221,21 @@ GtkAllocation allocation; gtk_widget_get_allocation(GTK_WIDGET(self), &allocation); gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); + + // Note we can't detect if a window is moved between monitors - this + // information is provided by Wayland but GTK only notifies us if the scale + // has changed, so moving between two monitors of the same scale doesn't + // provide any information. + + GdkWindow* window = + gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self))); + GdkMonitor* monitor = gdk_display_get_monitor_at_window( + gtk_widget_get_display(GTK_WIDGET(self)), window); fl_engine_send_window_metrics_event( - self->engine, self->view_id, allocation.width * scale_factor, + self->engine, + fl_display_monitor_get_display_id( + fl_engine_get_display_monitor(self->engine), monitor), + self->view_id, allocation.width * scale_factor, allocation.height * scale_factor, scale_factor); // Make sure the view has been realized and its size has been allocated before
diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_renderer.cc b/engine/src/flutter/shell/platform/linux/testing/mock_renderer.cc index 247537a..5ae2926 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_renderer.cc +++ b/engine/src/flutter/shell/platform/linux/testing/mock_renderer.cc
@@ -6,7 +6,6 @@ struct _FlMockRenderer { FlRenderer parent_instance; - FlMockRendererGetRefreshRate get_refresh_rate; }; struct _FlMockRenderable { @@ -33,22 +32,11 @@ // Implements FlRenderer::clear_current. static void fl_mock_renderer_clear_current(FlRenderer* renderer) {} -// Implements FlRenderer::get_refresh_rate. -static gdouble fl_mock_renderer_default_get_refresh_rate(FlRenderer* renderer) { - FlMockRenderer* self = FL_MOCK_RENDERER(renderer); - if (self->get_refresh_rate != nullptr) { - return self->get_refresh_rate(renderer); - } - return -1.0; -} - static void fl_mock_renderer_class_init(FlMockRendererClass* klass) { FL_RENDERER_CLASS(klass)->make_current = fl_mock_renderer_make_current; FL_RENDERER_CLASS(klass)->make_resource_current = fl_mock_renderer_make_resource_current; FL_RENDERER_CLASS(klass)->clear_current = fl_mock_renderer_clear_current; - FL_RENDERER_CLASS(klass)->get_refresh_rate = - fl_mock_renderer_default_get_refresh_rate; } static void fl_mock_renderer_init(FlMockRenderer* self) {} @@ -70,11 +58,9 @@ static void fl_mock_renderable_init(FlMockRenderable* self) {} // Creates a stub renderer -FlMockRenderer* fl_mock_renderer_new( - FlMockRendererGetRefreshRate get_refresh_rate) { +FlMockRenderer* fl_mock_renderer_new() { FlMockRenderer* self = FL_MOCK_RENDERER(g_object_new(fl_mock_renderer_get_type(), nullptr)); - self->get_refresh_rate = get_refresh_rate; return self; }
diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_renderer.h b/engine/src/flutter/shell/platform/linux/testing/mock_renderer.h index 9a2207e..5c6ada3 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_renderer.h +++ b/engine/src/flutter/shell/platform/linux/testing/mock_renderer.h
@@ -24,8 +24,7 @@ typedef gdouble (*FlMockRendererGetRefreshRate)(FlRenderer* renderer); -FlMockRenderer* fl_mock_renderer_new( - FlMockRendererGetRefreshRate get_refresh_rate = nullptr); +FlMockRenderer* fl_mock_renderer_new(); FlMockRenderable* fl_mock_renderable_new();
diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_window.cc b/engine/src/flutter/shell/platform/linux/testing/mock_window.cc index 8990230..ab7e383 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_window.cc +++ b/engine/src/flutter/shell/platform/linux/testing/mock_window.cc
@@ -12,12 +12,26 @@ mock = this; } +GdkDisplay* gdk_display_get_default() { + return GDK_DISPLAY(g_object_new(gdk_display_get_type(), nullptr)); +} + +void gdk_display_beep(GdkDisplay* display) {} + GdkWindowState gdk_window_get_state(GdkWindow* window) { return mock->gdk_window_get_state(window); } GdkDisplay* gdk_window_get_display(GdkWindow* window) { - return nullptr; + return GDK_DISPLAY(g_object_new(gdk_display_get_type(), nullptr)); +} + +int gdk_display_get_n_monitors(GdkDisplay* display) { + return 1; +} + +GdkMonitor* gdk_display_get_monitor(GdkDisplay* display, int n) { + return GDK_MONITOR(g_object_new(gdk_monitor_get_type(), nullptr)); } GdkMonitor* gdk_display_get_monitor_at_window(GdkDisplay* display,