Provide monitor information. (#161359)
Fixes https://github.com/flutter/flutter/issues/144230
This commit is contained in:
parent
bd1ebf2e14
commit
d14140f854
@ -44348,6 +44348,9 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_binary_messenger_test.cc + ../.
|
||||
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_binary_messenger_test.cc
|
||||
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
|
||||
|
@ -107,6 +107,7 @@ source_set("flutter_linux_sources") {
|
||||
"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 @@ executable("flutter_linux_unittests") {
|
||||
"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",
|
||||
|
120
engine/src/flutter/shell/platform/linux/fl_display_monitor.cc
Normal file
120
engine/src/flutter/shell/platform/linux/fl_display_monitor.cc
Normal file
@ -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));
|
||||
}
|
56
engine/src/flutter/shell/platform/linux/fl_display_monitor.h
Normal file
56
engine/src/flutter/shell/platform/linux/fl_display_monitor.h
Normal file
@ -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_
|
@ -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);
|
||||
}
|
@ -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 @@ struct _FlEngine {
|
||||
// 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 @@ FlRenderer* fl_engine_get_renderer(FlEngine* self) {
|
||||
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 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
|
||||
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 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* self) {
|
||||
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 fl_engine_add_view(FlEngine* self,
|
||||
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 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* self,
|
||||
}
|
||||
|
||||
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 @@ void fl_engine_send_window_metrics_event(FlEngine* self,
|
||||
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);
|
||||
}
|
||||
|
@ -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"
|
||||
@ -81,6 +82,16 @@ FlEngine* fl_engine_new_with_renderer(FlDartProject* project,
|
||||
*/
|
||||
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.
|
||||
@ -103,6 +114,18 @@ gboolean fl_engine_start(FlEngine* engine, GError** error);
|
||||
*/
|
||||
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.
|
||||
@ -213,6 +236,7 @@ void fl_engine_set_update_semantics_handler(
|
||||
/**
|
||||
* 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 @@ void fl_engine_set_update_semantics_handler(
|
||||
* 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,
|
||||
|
@ -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 @@ TEST(FlEngineTest, WindowMetrics) {
|
||||
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 @@ TEST(FlEngineTest, WindowMetrics) {
|
||||
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);
|
||||
}
|
||||
|
@ -381,11 +381,6 @@ void fl_renderer_clear_current(FlRenderer* self) {
|
||||
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);
|
||||
|
||||
|
@ -55,16 +55,6 @@ struct _FlRendererClass {
|
||||
* @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_render(FlRenderer* renderer,
|
||||
*/
|
||||
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_
|
||||
|
@ -39,24 +39,6 @@ static void fl_renderer_gdk_clear_current(FlRenderer* renderer) {
|
||||
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 @@ static void fl_renderer_gdk_class_init(FlRendererGdkClass* klass) {
|
||||
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) {}
|
||||
|
@ -19,18 +19,11 @@ static void fl_renderer_headless_make_resource_current(FlRenderer* renderer) {}
|
||||
// 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) {}
|
||||
|
@ -93,20 +93,6 @@ TEST(FlRendererTest, RestoresGLState) {
|
||||
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;
|
||||
|
||||
|
@ -221,8 +221,21 @@ static void handle_geometry_changed(FlView* self) {
|
||||
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
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
struct _FlMockRenderer {
|
||||
FlRenderer parent_instance;
|
||||
FlMockRendererGetRefreshRate get_refresh_rate;
|
||||
};
|
||||
|
||||
struct _FlMockRenderable {
|
||||
@ -33,22 +32,11 @@ static void fl_mock_renderer_make_resource_current(FlRenderer* renderer) {}
|
||||
// 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_class_init(FlMockRenderableClass* klass) {}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@ G_DECLARE_FINAL_TYPE(FlMockRenderable,
|
||||
|
||||
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();
|
||||
|
||||
|
@ -12,12 +12,26 @@ MockWindow::MockWindow() {
|
||||
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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user