monitor-manager: Rework default scale factor selection

From the scale factors available to it, Mutter will now try to select
the scale factor that makes the UI's size as close as possible to the
size it would be, w/o scaling, on a display at 135 PPI (for mobile
displays) or at 110 PPI (for stationary displays)

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2653>
This commit is contained in:
Adrian Vovk 2022-10-07 01:46:04 -04:00 committed by Marge Bot
parent 53126bf008
commit 2f1dd049bf

View File

@ -1804,74 +1804,97 @@ meta_monitor_calculate_crtc_pos (MetaMonitor *monitor,
out_y); out_y);
} }
/* The minimum resolution at which we turn on a window-scale of 2 */ /*
#define HIDPI_LIMIT 192 * We choose a default scale factor such that the UI is as big
* as it would be on a display with this DPI without scaling.
*
* Through experiementing, a value of 135 has been found to best
* line up with the UI size chosen as default by other operating
* systems (macOS, Android, iOS, Windows) and the community-decided
* "known-good" scale factors for GNOME for various mobile devices
* such as phones, tablets, and laptops
*/
#define UI_SCALE_MOBILE_TARGET_DPI 135
/* /*
* The minimum screen height at which we turn on a window-scale of 2; * People tend to sit further away from larger stationary displays
* below this there just isn't enough vertical real estate for GNOME * than they do from mobile displays, so a UI of an identical size to
* apps to work, and it's better to just be tiny * a mobile device has a smaller angular size and thus seems to be too
* small.
*
* The largest mainstream laptops have screens ~17in, and HiDPI external
* monitors start at ~23in, so 20in is a good boundary point
*/ */
#define HIDPI_MIN_HEIGHT 1200 #define UI_SCALE_LARGE_TARGET_DPI 110
#define UI_SCALE_LARGE_MIN_SIZE_INCHES 20
/* From http://en.wikipedia.org/wiki/4K_resolution#Resolutions_of_common_formats */
#define SMALLEST_4K_WIDTH 3656
static float static float
calculate_scale (MetaMonitor *monitor, calculate_scale (MetaMonitor *monitor,
MetaMonitorMode *monitor_mode, MetaMonitorMode *monitor_mode,
MetaMonitorScalesConstraint constraints) MetaMonitorScalesConstraint constraints)
{ {
int resolution_width, resolution_height; int width_px, height_px, width_mm, height_mm;
int width_mm, height_mm; float diag_inches;
int scale; g_autofree float *scales = NULL;
int n_scales;
scale = 1.0; float best_scale, best_dpi;
int target_dpi;
meta_monitor_mode_get_resolution (monitor_mode,
&resolution_width,
&resolution_height);
if (resolution_height < HIDPI_MIN_HEIGHT)
return scale;
/* 4K TV */
switch (meta_monitor_get_connector_type (monitor))
{
case META_CONNECTOR_TYPE_HDMIA:
case META_CONNECTOR_TYPE_HDMIB:
if (resolution_width < SMALLEST_4K_WIDTH)
return scale;
break;
default:
break;
}
meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
/* /*
* Somebody encoded the aspect ratio (16/9 or 16/10) instead of the physical * Somebody encoded the aspect ratio (16/9 or 16/10) instead of the physical
* size. * size. We'll be unable to select an appropriate scale factor.
*/ */
if (meta_monitor_has_aspect_as_size (monitor)) if (meta_monitor_has_aspect_as_size (monitor))
return scale; return 1.0;
if (width_mm > 0 && height_mm > 0) /* Compute display's diagonal size in inches */
meta_monitor_get_physical_dimensions (monitor, &width_mm, &height_mm);
if (width_mm == 0 || height_mm == 0)
return 1.0;
diag_inches = sqrtf (width_mm * width_mm + height_mm * height_mm) / 25.4;
/* Pick the appropriate target DPI based on screen size */
if (diag_inches < UI_SCALE_LARGE_MIN_SIZE_INCHES)
target_dpi = UI_SCALE_MOBILE_TARGET_DPI;
else
target_dpi = UI_SCALE_LARGE_TARGET_DPI;
meta_monitor_mode_get_resolution (monitor_mode, &width_px, &height_px);
/* We'll only be considering the supported scale factors */
scales = meta_monitor_calculate_supported_scales (monitor, monitor_mode,
constraints, &n_scales);
best_scale = scales[0];
for (int i = 0; i < n_scales; i++)
{ {
double dpi_x, dpi_y; float width_scaled, height_scaled, diag_scaled, dpi;
dpi_x = (double) resolution_width / (width_mm / 25.4);
dpi_y = (double) resolution_height / (height_mm / 25.4);
/* /*
* We don't completely trust these values so both must be high, and never * Compute the logical resolution of the display for this
* pick higher ratio than 2 automatically. * scale factor
*/ */
if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT) width_scaled = (float) width_px / scales[i];
scale = 2.0; height_scaled = (float) height_px / scales[i];
/* Compute the number of logical pixels across the display's diagonal */
diag_scaled = sqrtf (width_scaled * width_scaled +
height_scaled * height_scaled);
/*
* Computes the display's logical DPI - the number of logical pixels
* per inch on the display's diagonal
*/
dpi = diag_scaled / diag_inches;
/* Pick the scale factor whose logical DPI is closest to the optimal value */
if (i == 0 || fabsf (dpi - target_dpi) < fabsf (best_dpi - target_dpi))
{
best_scale = scales[i];
best_dpi = dpi;
}
} }
return scale; return best_scale;
} }
float float