Skip to content

Commit afa6b41

Browse files
robert-ancellmaheshj01
authored andcommitted
Provide monitor information. (flutter#161359)
Fixes flutter#144230
1 parent ef6faff commit afa6b41

17 files changed

+367
-101
lines changed

engine/src/flutter/ci/licenses_golden/licenses_flutter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44348,6 +44348,9 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_binary_messenger_test.cc + ../.
4434844348
ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project.cc + ../../../flutter/LICENSE
4434944349
ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project_private.h + ../../../flutter/LICENSE
4435044350
ORIGIN: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc + ../../../flutter/LICENSE
44351+
ORIGIN: ../../../flutter/shell/platform/linux/fl_display_monitor.cc + ../../../flutter/LICENSE
44352+
ORIGIN: ../../../flutter/shell/platform/linux/fl_display_monitor.h + ../../../flutter/LICENSE
44353+
ORIGIN: ../../../flutter/shell/platform/linux/fl_display_monitor_test.cc + ../../../flutter/LICENSE
4435144354
ORIGIN: ../../../flutter/shell/platform/linux/fl_engine.cc + ../../../flutter/LICENSE
4435244355
ORIGIN: ../../../flutter/shell/platform/linux/fl_engine_private.h + ../../../flutter/LICENSE
4435344356
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
4731747320
FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
4731847321
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_private.h
4731947322
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
47323+
FILE: ../../../flutter/shell/platform/linux/fl_display_monitor.cc
47324+
FILE: ../../../flutter/shell/platform/linux/fl_display_monitor.h
47325+
FILE: ../../../flutter/shell/platform/linux/fl_display_monitor_test.cc
4732047326
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
4732147327
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
4732247328
FILE: ../../../flutter/shell/platform/linux/fl_engine_test.cc

engine/src/flutter/shell/platform/linux/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ source_set("flutter_linux_sources") {
107107
"fl_binary_codec.cc",
108108
"fl_binary_messenger.cc",
109109
"fl_dart_project.cc",
110+
"fl_display_monitor.cc",
110111
"fl_engine.cc",
111112
"fl_event_channel.cc",
112113
"fl_framebuffer.cc",
@@ -216,6 +217,7 @@ executable("flutter_linux_unittests") {
216217
"fl_binary_codec_test.cc",
217218
"fl_binary_messenger_test.cc",
218219
"fl_dart_project_test.cc",
220+
"fl_display_monitor_test.cc",
219221
"fl_engine_test.cc",
220222
"fl_event_channel_test.cc",
221223
"fl_framebuffer_test.cc",
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/linux/fl_display_monitor.h"
6+
#include "flutter/shell/platform/linux/fl_engine_private.h"
7+
8+
struct _FlDisplayMonitor {
9+
GObject parent_instance;
10+
11+
// Engine being updated.
12+
GWeakRef engine;
13+
14+
// Display being monitored.
15+
GdkDisplay* display;
16+
17+
// Mapping of GdkMonitor to display IDs.
18+
GHashTable* display_ids_by_monitor;
19+
20+
// Next ID to assign to a new monitor.
21+
FlutterEngineDisplayId next_display_id;
22+
};
23+
24+
G_DEFINE_TYPE(FlDisplayMonitor, fl_display_monitor, G_TYPE_OBJECT)
25+
26+
// Send the current monitor state to the engine.
27+
static void notify_display_update(FlDisplayMonitor* self) {
28+
g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
29+
if (engine == nullptr) {
30+
return;
31+
}
32+
33+
int n_monitors = gdk_display_get_n_monitors(self->display);
34+
g_autofree FlutterEngineDisplay* displays =
35+
g_new0(FlutterEngineDisplay, n_monitors);
36+
for (int i = 0; i < n_monitors; i++) {
37+
FlutterEngineDisplay* display = &displays[i];
38+
39+
GdkMonitor* monitor = gdk_display_get_monitor(self->display, i);
40+
FlutterEngineDisplayId display_id = GPOINTER_TO_INT(
41+
g_hash_table_lookup(self->display_ids_by_monitor, monitor));
42+
if (display_id == 0) {
43+
display_id = self->next_display_id;
44+
g_hash_table_insert(self->display_ids_by_monitor, g_object_ref(monitor),
45+
GINT_TO_POINTER(display_id));
46+
self->next_display_id++;
47+
}
48+
49+
GdkRectangle geometry;
50+
gdk_monitor_get_geometry(monitor, &geometry);
51+
52+
display->struct_size = sizeof(FlutterEngineDisplay);
53+
display->display_id = display_id;
54+
display->single_display = false;
55+
display->refresh_rate = gdk_monitor_get_refresh_rate(monitor) / 1000.0;
56+
display->width = geometry.width;
57+
display->height = geometry.height;
58+
display->device_pixel_ratio = gdk_monitor_get_scale_factor(monitor);
59+
}
60+
61+
fl_engine_notify_display_update(engine, displays, n_monitors);
62+
}
63+
64+
static void monitor_added_cb(FlDisplayMonitor* self, GdkMonitor* monitor) {
65+
notify_display_update(self);
66+
}
67+
68+
static void monitor_removed_cb(FlDisplayMonitor* self, GdkMonitor* monitor) {
69+
g_hash_table_remove(self->display_ids_by_monitor, monitor);
70+
notify_display_update(self);
71+
}
72+
73+
static void fl_display_monitor_dispose(GObject* object) {
74+
FlDisplayMonitor* self = FL_DISPLAY_MONITOR(object);
75+
76+
g_weak_ref_clear(&self->engine);
77+
g_clear_object(&self->display);
78+
g_clear_pointer(&self->display_ids_by_monitor, g_hash_table_unref);
79+
80+
G_OBJECT_CLASS(fl_display_monitor_parent_class)->dispose(object);
81+
}
82+
83+
static void fl_display_monitor_class_init(FlDisplayMonitorClass* klass) {
84+
GObjectClass* object_class = G_OBJECT_CLASS(klass);
85+
object_class->dispose = fl_display_monitor_dispose;
86+
}
87+
88+
static void fl_display_monitor_init(FlDisplayMonitor* self) {
89+
self->display_ids_by_monitor = g_hash_table_new_full(
90+
g_direct_hash, g_direct_equal, g_object_unref, nullptr);
91+
self->next_display_id = 1;
92+
}
93+
94+
FlDisplayMonitor* fl_display_monitor_new(FlEngine* engine,
95+
GdkDisplay* display) {
96+
FlDisplayMonitor* self =
97+
FL_DISPLAY_MONITOR(g_object_new(fl_display_monitor_get_type(), nullptr));
98+
g_weak_ref_init(&self->engine, engine);
99+
self->display = GDK_DISPLAY(g_object_ref(display));
100+
return self;
101+
}
102+
103+
void fl_display_monitor_start(FlDisplayMonitor* self) {
104+
g_return_if_fail(FL_IS_DISPLAY_MONITOR(self));
105+
106+
g_signal_connect_object(self->display, "monitor-added",
107+
G_CALLBACK(monitor_added_cb), self,
108+
G_CONNECT_SWAPPED);
109+
g_signal_connect_object(self->display, "monitor-removed",
110+
G_CALLBACK(monitor_removed_cb), self,
111+
G_CONNECT_SWAPPED);
112+
notify_display_update(self);
113+
}
114+
115+
FlutterEngineDisplayId fl_display_monitor_get_display_id(FlDisplayMonitor* self,
116+
GdkMonitor* monitor) {
117+
g_return_val_if_fail(FL_IS_DISPLAY_MONITOR(self), 0);
118+
return GPOINTER_TO_INT(
119+
g_hash_table_lookup(self->display_ids_by_monitor, monitor));
120+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_DISPLAY_MONITOR_H_
6+
#define FLUTTER_SHELL_PLATFORM_LINUX_FL_DISPLAY_MONITOR_H_
7+
8+
#include <gdk/gdk.h>
9+
10+
#include "flutter/shell/platform/embedder/embedder.h"
11+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
12+
13+
G_BEGIN_DECLS
14+
15+
G_DECLARE_FINAL_TYPE(FlDisplayMonitor,
16+
fl_display_monitor,
17+
FL,
18+
DISPLAY_MONITOR,
19+
GObject);
20+
21+
/**
22+
* fl_display_monitor_new:
23+
* @engine: engine to update.
24+
* @display: display to monitor.
25+
*
26+
* Creates a new object to keep the engine updated with the currently used
27+
* displays. In GDK, a display is called a "monitor".
28+
*
29+
* Returns: a new #FlDisplayMontior.
30+
*/
31+
FlDisplayMonitor* fl_display_monitor_new(FlEngine* engine, GdkDisplay* display);
32+
33+
/**
34+
* fl_display_monitor_start:
35+
* @monitor: an #FlDisplayMonitor.
36+
*
37+
* Start monitoring for display changes.
38+
*/
39+
void fl_display_monitor_start(FlDisplayMonitor* monitor);
40+
41+
/**
42+
* fl_display_monitor_get_display_id:
43+
* @monitor: an #FlDisplayMonitor.
44+
* @gdk_monitor: GDK monitor to get display ID for.
45+
*
46+
* Get the ID Flutter is using for a given monitor.
47+
*
48+
* Returns: an ID or 0 if unknown.
49+
*/
50+
FlutterEngineDisplayId fl_display_monitor_get_display_id(
51+
FlDisplayMonitor* monitor,
52+
GdkMonitor* gdk_monitor);
53+
54+
G_END_DECLS
55+
56+
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_DISPLAY_MONITOR_H_
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/platform/linux/fl_display_monitor.h"
6+
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
7+
#include "flutter/shell/platform/linux/fl_engine_private.h"
8+
9+
#include "gtest/gtest.h"
10+
11+
TEST(FlDisplayMonitorTest, Test) {
12+
g_autoptr(FlDartProject) project = fl_dart_project_new();
13+
g_autoptr(FlEngine) engine = fl_engine_new(project);
14+
15+
g_autoptr(GError) error = nullptr;
16+
EXPECT_TRUE(fl_engine_start(engine, &error));
17+
EXPECT_EQ(error, nullptr);
18+
19+
bool called = false;
20+
fl_engine_get_embedder_api(engine)->NotifyDisplayUpdate = MOCK_ENGINE_PROC(
21+
NotifyDisplayUpdate,
22+
([&called](auto engine, FlutterEngineDisplaysUpdateType update_type,
23+
const FlutterEngineDisplay* displays, size_t displays_length) {
24+
called = true;
25+
26+
EXPECT_EQ(displays_length, 1u);
27+
28+
return kSuccess;
29+
}));
30+
31+
g_autoptr(FlDisplayMonitor) monitor =
32+
fl_display_monitor_new(engine, gdk_display_get_default());
33+
EXPECT_FALSE(called);
34+
fl_display_monitor_start(monitor);
35+
EXPECT_TRUE(called);
36+
}

engine/src/flutter/shell/platform/linux/fl_engine.cc

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flutter/shell/platform/embedder/embedder.h"
1313
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
1414
#include "flutter/shell/platform/linux/fl_dart_project_private.h"
15+
#include "flutter/shell/platform/linux/fl_display_monitor.h"
1516
#include "flutter/shell/platform/linux/fl_engine_private.h"
1617
#include "flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h"
1718
#include "flutter/shell/platform/linux/fl_platform_handler.h"
@@ -41,6 +42,9 @@ struct _FlEngine {
4142
// The project this engine is running.
4243
FlDartProject* project;
4344

45+
// Watches for monitors changes to update engine.
46+
FlDisplayMonitor* display_monitor;
47+
4448
// Renders the Flutter app.
4549
FlRenderer* renderer;
4650

@@ -532,6 +536,11 @@ FlRenderer* fl_engine_get_renderer(FlEngine* self) {
532536
return self->renderer;
533537
}
534538

539+
FlDisplayMonitor* fl_engine_get_display_monitor(FlEngine* self) {
540+
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
541+
return self->display_monitor;
542+
}
543+
535544
gboolean fl_engine_start(FlEngine* self, GError** error) {
536545
g_return_val_if_fail(FL_IS_ENGINE(self), FALSE);
537546

@@ -642,23 +651,9 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
642651
g_warning("Failed to enable accessibility features on Flutter engine");
643652
}
644653

645-
gdouble refresh_rate = fl_renderer_get_refresh_rate(self->renderer);
646-
// FlutterEngineDisplay::refresh_rate expects 0 if the refresh rate is
647-
// unknown.
648-
if (refresh_rate <= 0.0) {
649-
refresh_rate = 0.0;
650-
}
651-
FlutterEngineDisplay display = {};
652-
display.struct_size = sizeof(FlutterEngineDisplay);
653-
display.display_id = 0;
654-
display.single_display = true;
655-
display.refresh_rate = refresh_rate;
656-
657-
result = self->embedder_api.NotifyDisplayUpdate(
658-
self->engine, kFlutterEngineDisplaysUpdateTypeStartup, &display, 1);
659-
if (result != kSuccess) {
660-
g_warning("Failed to notify display update to Flutter engine: %d", result);
661-
}
654+
self->display_monitor =
655+
fl_display_monitor_new(self, gdk_display_get_default());
656+
fl_display_monitor_start(self->display_monitor);
662657

663658
return TRUE;
664659
}
@@ -667,6 +662,19 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* self) {
667662
return &(self->embedder_api);
668663
}
669664

665+
void fl_engine_notify_display_update(FlEngine* self,
666+
const FlutterEngineDisplay* displays,
667+
size_t displays_length) {
668+
g_return_if_fail(FL_IS_ENGINE(self));
669+
670+
FlutterEngineResult result = self->embedder_api.NotifyDisplayUpdate(
671+
self->engine, kFlutterEngineDisplaysUpdateTypeStartup, displays,
672+
displays_length);
673+
if (result != kSuccess) {
674+
g_warning("Failed to notify display update to Flutter engine: %d", result);
675+
}
676+
}
677+
670678
FlutterViewId fl_engine_add_view(FlEngine* self,
671679
size_t width,
672680
size_t height,
@@ -681,11 +689,16 @@ FlutterViewId fl_engine_add_view(FlEngine* self,
681689
FlutterViewId view_id = self->next_view_id;
682690
self->next_view_id++;
683691

692+
// We don't know which display this view will open on, so set to zero and this
693+
// will be updated in a following FlutterWindowMetricsEvent
694+
FlutterEngineDisplayId display_id = 0;
695+
684696
FlutterWindowMetricsEvent metrics;
685697
metrics.struct_size = sizeof(FlutterWindowMetricsEvent);
686698
metrics.width = width;
687699
metrics.height = height;
688700
metrics.pixel_ratio = pixel_ratio;
701+
metrics.display_id = display_id;
689702
metrics.view_id = view_id;
690703
FlutterAddViewInfo info;
691704
info.struct_size = sizeof(FlutterAddViewInfo);
@@ -881,6 +894,7 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* self,
881894
}
882895

883896
void fl_engine_send_window_metrics_event(FlEngine* self,
897+
FlutterEngineDisplayId display_id,
884898
FlutterViewId view_id,
885899
size_t width,
886900
size_t height,
@@ -896,6 +910,7 @@ void fl_engine_send_window_metrics_event(FlEngine* self,
896910
event.width = width;
897911
event.height = height;
898912
event.pixel_ratio = pixel_ratio;
913+
event.display_id = display_id;
899914
event.view_id = view_id;
900915
self->embedder_api.SendWindowMetricsEvent(self->engine, &event);
901916
}

0 commit comments

Comments
 (0)