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,