Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions engine/src/flutter/ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -44347,6 +44347,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
Expand Down Expand Up @@ -47315,6 +47318,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
Expand Down
2 changes: 2 additions & 0 deletions engine/src/flutter/shell/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
120 changes: 120 additions & 0 deletions engine/src/flutter/shell/platform/linux/fl_display_monitor.cc
Original file line number Diff line number Diff line change
@@ -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 changes: 56 additions & 0 deletions engine/src/flutter/shell/platform/linux/fl_display_monitor.h
Original file line number Diff line number Diff line change
@@ -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_
36 changes: 36 additions & 0 deletions engine/src/flutter/shell/platform/linux/fl_display_monitor_test.cc
Original file line number Diff line number Diff line change
@@ -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);
}
49 changes: 32 additions & 17 deletions engine/src/flutter/shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}
Expand Down
Loading
Loading