Commit 3e8d0204 authored by Marco Trevisan's avatar Marco Trevisan 🎺 Committed by Jonas Ådahl

monitor: Dynamically calculate supported scales per resolution

When using logical sized monitors we are allowed to use fractional scaling
but only if the resulting scaled logical monitor size is in integer form.
So, in order to get this, we allow to scale the monitor to up to
8 fractional values per integer, doing some computation in order to
fetch the nearest values which are closer to the scaling factors we can
permit.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
parent b2a530b3
......@@ -27,6 +27,10 @@
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-settings-private.h"
#define SCALE_FACTORS_PER_INTEGER 8
#define MINIMUM_SCALE_FACTOR 0.5f
#define MAXIMUM_SCALE_FACTOR 4.0f
typedef struct _MetaMonitorMode
{
MetaMonitorModeSpec spec;
......@@ -1336,37 +1340,112 @@ meta_monitor_calculate_mode_scale (MetaMonitor *monitor,
return calculate_scale (monitor, monitor_mode);
}
static float
get_closest_scale_factor_for_resolution (float width,
float height,
float scale,
float scale_step)
{
unsigned int i, j;
float scaled_h;
float scaled_w;
float best_scale;
int base_scaled_w;
gboolean limit_exceeded;
gboolean found_one;
best_scale = 0;
scaled_w = width / scale;
scaled_h = height / scale;
if (scale < MINIMUM_SCALE_FACTOR || scale > MAXIMUM_SCALE_FACTOR)
goto out;
if (floorf (scaled_w) == scaled_w && floorf (scaled_h) == scaled_h)
return scale;
i = 0;
found_one = FALSE;
limit_exceeded = FALSE;
base_scaled_w = floorf (scaled_w);
do
{
for (j = 0; j < 2; j++)
{
float current_scale;
int offset = i * (j ? 1 : -1);
scaled_w = base_scaled_w + offset;
current_scale = width / scaled_w;
scaled_h = height / current_scale;
if (current_scale >= scale + scale_step ||
current_scale <= scale - scale_step ||
current_scale < MINIMUM_SCALE_FACTOR ||
current_scale > MAXIMUM_SCALE_FACTOR)
{
limit_exceeded = TRUE;
continue;
}
if (floorf (scaled_h) == scaled_h)
{
found_one = TRUE;
if (fabsf (current_scale - scale) < fabsf (best_scale - scale))
best_scale = current_scale;
}
}
i++;
}
while (!found_one && !limit_exceeded);
out:
return best_scale;
}
float *
meta_monitor_calculate_supported_scales (MetaMonitor *monitor,
MetaMonitorMode *monitor_mode,
MetaMonitorScalesConstraint constraints,
int *n_supported_scales)
{
unsigned int i;
unsigned int i, j;
int width, height;
float scale_steps;
GArray *supported_scales;
static const float all_scales[] = {
1.0,
1.5,
2.0
};
meta_monitor_mode_get_resolution (monitor_mode, &width, &height);
scale_steps = 1.0 / (float) SCALE_FACTORS_PER_INTEGER;
supported_scales = g_array_new (FALSE, FALSE, sizeof (float));
for (i = 0; i < G_N_ELEMENTS (all_scales); i++)
{
float scale = all_scales[i];
if ((constraints & META_MONITOR_SCALES_CONSTRAINT_NO_FRAC) &&
fmodf (scale, 1.0) != 0.0)
continue;
if (fmodf (width, scale) != 0.0 || fmodf (height, scale) != 0.0)
continue;
meta_monitor_mode_get_resolution (monitor_mode, &width, &height);
g_array_append_val (supported_scales, scale);
for (i = floorf (MINIMUM_SCALE_FACTOR);
i <= ceilf (MAXIMUM_SCALE_FACTOR);
i++)
{
for (j = 0; j < SCALE_FACTORS_PER_INTEGER; j++)
{
float scale;
float scale_value = i + j * scale_steps;
if ((constraints & META_MONITOR_SCALES_CONSTRAINT_NO_FRAC) &&
fmodf (scale_value, 1.0) != 0.0)
{
continue;
}
scale = get_closest_scale_factor_for_resolution (width,
height,
scale_value,
scale_steps);
if (scale > 0.0f)
g_array_append_val (supported_scales, scale);
}
}
*n_supported_scales = supported_scales->len;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment