-
Notifications
You must be signed in to change notification settings - Fork 6k
Add a Display API to dart:ui that reports the physical size, DPR, and refresh rate of the main display
#41685
Changes from all commits
38c8574
5c6f70e
91d7e81
7b9f681
878dcfb
6f1a0bb
123deaf
d0224c9
67958ed
04418a4
3e87708
806a4ae
5f2e0c1
be4731d
200f091
ea76da6
fc3b8f4
8f62507
ad25b20
a7602b4
40bb6c9
1f2e889
400b50a
9df181c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,6 +149,26 @@ class PlatformDispatcher { | |
| _onPlatformConfigurationChangedZone = Zone.current; | ||
| } | ||
|
|
||
| /// The current list of displays. | ||
| /// | ||
| /// If any of their configurations change, [onMetricsChanged] will be called. | ||
| /// | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe document some of the current platform-specific limitations? Presumably, this is just empty for desktops right now?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added some docs.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same caveat should likely also be documented on the FlutterView.display property? |
||
| /// To get the display for a [FlutterView], use [FlutterView.display]. | ||
| /// | ||
| /// Platforms may limit what information is available to the application with | ||
| /// regard to secondary displays and/or displays that do not have an active | ||
| /// application window. | ||
| /// | ||
| /// Presently, on Android and Web this collection will only contain the | ||
| /// display that the current window is on. On iOS, it will only contains the | ||
| /// main display on the phone or tablet. On Desktop, it will contain only | ||
| /// a main display with a valid refresh rate but invalid size and device | ||
| /// pixel ratio values. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to make these values missing or null instead of invalid (which I assume means incorrect).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't want to make them null, since it will be harder to migrate them away from nullable later if people start treating them as nullable (e.g. they add The plan is to implement them for desktop sooner than later. |
||
| // TODO(dnfield): Update these docs when https://github.com/flutter/flutter/issues/125939 | ||
| // and https://github.com/flutter/flutter/issues/125938 are resolved. | ||
| Iterable<Display> get displays => _displays.values; | ||
| final Map<int, Display> _displays = <int, Display>{}; | ||
|
|
||
| /// The current list of views, including top level platform windows used by | ||
| /// the application. | ||
| /// | ||
|
|
@@ -215,6 +235,17 @@ class PlatformDispatcher { | |
| _onMetricsChangedZone = Zone.current; | ||
| } | ||
|
|
||
| // Called from the engine, via hooks.dart. | ||
| // | ||
| // Updates the available displays. | ||
| void _updateDisplays(List<Display> displays) { | ||
| _displays.clear(); | ||
| for (final Display display in displays) { | ||
| _displays[display.id] = display; | ||
| } | ||
| _invoke(onMetricsChanged, _onMetricsChangedZone); | ||
| } | ||
|
|
||
| // Called from the engine, via hooks.dart | ||
| // | ||
| // Updates the metrics of the window with the given id. | ||
|
|
@@ -239,6 +270,7 @@ class PlatformDispatcher { | |
| List<double> displayFeaturesBounds, | ||
| List<int> displayFeaturesType, | ||
| List<int> displayFeaturesState, | ||
| int displayId, | ||
| ) { | ||
| final _ViewConfiguration previousConfiguration = | ||
| _viewConfigurations[id] ?? const _ViewConfiguration(); | ||
|
|
@@ -283,6 +315,7 @@ class PlatformDispatcher { | |
| state: displayFeaturesState, | ||
| devicePixelRatio: devicePixelRatio, | ||
| ), | ||
| displayId: displayId, | ||
| ); | ||
| _invoke(onMetricsChanged, _onMetricsChangedZone); | ||
| } | ||
|
|
@@ -1318,6 +1351,7 @@ class _ViewConfiguration { | |
| this.padding = ViewPadding.zero, | ||
| this.gestureSettings = const GestureSettings(), | ||
| this.displayFeatures = const <DisplayFeature>[], | ||
| this.displayId = 0, | ||
| }); | ||
|
|
||
| /// Copy this configuration with some fields replaced. | ||
|
|
@@ -1332,6 +1366,7 @@ class _ViewConfiguration { | |
| ViewPadding? padding, | ||
| GestureSettings? gestureSettings, | ||
| List<DisplayFeature>? displayFeatures, | ||
| int? displayId, | ||
| }) { | ||
| return _ViewConfiguration( | ||
| view: view ?? this.view, | ||
|
|
@@ -1344,11 +1379,16 @@ class _ViewConfiguration { | |
| padding: padding ?? this.padding, | ||
| gestureSettings: gestureSettings ?? this.gestureSettings, | ||
| displayFeatures: displayFeatures ?? this.displayFeatures, | ||
| displayId: displayId ?? this.displayId, | ||
| ); | ||
| } | ||
|
|
||
| final FlutterView? view; | ||
|
|
||
| /// The identifier for a display for this view, in | ||
| /// [PlatformDispatcher._displays]. | ||
| final int displayId; | ||
|
|
||
| /// The pixel density of the output surface. | ||
| final double devicePixelRatio; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,40 @@ | |
| // found in the LICENSE file. | ||
| part of dart.ui; | ||
|
|
||
| /// A configurable display that a [FlutterView] renders on. | ||
| /// | ||
| /// Use [FlutterView.display] to get the current display for that view. | ||
| class Display { | ||
| const Display._({ | ||
| required this.id, | ||
| required this.devicePixelRatio, | ||
| required this.size, | ||
| required this.refreshRate, | ||
| }); | ||
|
|
||
| /// A unique identifier for this display. | ||
| /// | ||
| /// This identifier is unique among a list of displays the Flutter framework | ||
| /// is aware of, and is not derived from any platform specific identifiers for | ||
| /// displays. | ||
| final int id; | ||
|
|
||
| /// The device pixel ratio of this display. | ||
| /// | ||
| /// This value is the same as the value of [FlutterView.devicePixelRatio] for | ||
| /// all view objects attached to this display. | ||
| final double devicePixelRatio; | ||
|
|
||
| /// The physical size of this display. | ||
| final Size size; | ||
|
|
||
| /// The refresh rate in FPS of this display. | ||
| final double refreshRate; | ||
|
|
||
| @override | ||
| String toString() => 'Display(id: $id, size: $size, devicePixelRatio: $devicePixelRatio, refreshRate: $refreshRate)'; | ||
| } | ||
|
|
||
| /// A view into which a Flutter [Scene] is drawn. | ||
| /// | ||
| /// Each [FlutterView] has its own layer tree that is rendered | ||
|
|
@@ -67,6 +101,12 @@ class FlutterView { | |
| return platformDispatcher._viewConfigurations[viewId]!; | ||
| } | ||
|
|
||
| /// The [Display] this view is drawn in. | ||
| Display get display { | ||
| assert(platformDispatcher._displays.containsKey(_viewConfiguration.displayId)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this fail if the embedder doesn't provide display information? (I'm not sure Windows, macOS, or Linux provide display information)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now they provide a display that is not quite valid. But yes, the assert would fire if the embedder failed to provide a display.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we make this property nullable and force the caller to have some fallback logic if display information isn't available?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should just implement it. Making it nullable now and non-nullable later is harder once people start using it (it results in compilation errors, which make the migration in google's monorepo harder). I don't expect it to take long to implement the desktop portion of this, I just don't want to delay this patch further and it's already fairly large.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, what does this currently return for unimplemented platforms? Have we verified that this is implementable on all desktop platforms we want to support? Wayland comes to mind as a platform that may not be able to tell us what display we are on (I haven't verified this, this is just from what I have heard). If that turns out to be true, what would we expect this getter to do? For that case, it may be nicer if this can just be null.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now it's returning -1 for the DPR, width, and height, and a real refresh rate/display ID.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On Linux, we can indeed get the width and height of at least the display the application is rendering to, and probably all displays. Even if Wayland doesn't have an API for this, you have to tell Wayland to connect to a particular display adapter, and it will be possible to query the information about the display size from that adapter. GTK also has an API for this.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the GTK API?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I meant GDK :) What the Linux embedding uses for windowing etc. |
||
| return platformDispatcher._displays[_viewConfiguration.displayId]!; | ||
| } | ||
|
|
||
| /// The number of device pixels for each logical pixel for the screen this | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a little bit of duplicated information available now as dpr as also available via the display getter now. It's probably not an issue, but a little strange? Presumably, both will always have the same value?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DPR really belongs on the display. I'm half tempted to deprecate it on View, but that seems like it'd create a lot of unnecessary churn. But yes, DPR on the view will always match DPR from the display.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might want to add to the dart doc to DPR on view that says window is the prefered way if you indeed think that is the case.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need the DPR if you want to figure out logical pixel sizes. I'll document that they're the same.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added some docs. |
||
| /// view is displayed on. | ||
| /// | ||
|
|
@@ -92,6 +132,8 @@ class FlutterView { | |
| /// | ||
| /// * [WidgetsBindingObserver], for a mechanism at the widgets layer to | ||
| /// observe when this value changes. | ||
| /// * [Display.devicePixelRatio], which reports the DPR of the display. | ||
| /// The value here is equal to the value on the [display.devicePixelRatio]. | ||
| double get devicePixelRatio => _viewConfiguration.devicePixelRatio; | ||
|
|
||
| /// The dimensions and location of the rectangle into which the scene rendered | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.