Forked from
PureOS / Packages / gnome-control-center
2812 commits behind, 1166 commits ahead of the upstream repository.
-
Marco Trevisan (Treviño) authored
Ensure the user is requested to apply changes if the requested configuration uses UI scaling and the current widget scaling value doesn't match the requested one. LP: #1887707
Marco Trevisan (Treviño) authoredEnsure the user is requested to apply changes if the requested configuration uses UI scaling and the current widget scaling value doesn't match the requested one. LP: #1887707
0024-display-Allow-fractional-scaling-to-be-enabled.patch 18.61 KiB
From: Robert Ancell <robert.ancell@canonical.com>
Date: Sun, 15 Mar 2020 09:07:51 +0100
Subject: [PATCH 24/26] display: Allow fractional scaling to be enabled
---
panels/display/cc-display-config-dbus.c | 16 +++
panels/display/cc-display-config.c | 237 ++++++++++++++++++++++++++++++++
panels/display/cc-display-config.h | 5 +
panels/display/cc-display-settings.c | 28 +++-
panels/display/cc-display-settings.ui | 16 +++
5 files changed, 301 insertions(+), 1 deletion(-)
diff --git a/panels/display/cc-display-config-dbus.c b/panels/display/cc-display-config-dbus.c
index fc050a3..7eda67a 100644
--- a/panels/display/cc-display-config-dbus.c
+++ b/panels/display/cc-display-config-dbus.c
@@ -887,6 +887,7 @@ struct _CcDisplayConfigDBus
gboolean supports_changing_layout_mode;
gboolean global_scale_required;
CcDisplayLayoutMode layout_mode;
+ gint legacy_ui_scale;
GList *monitors;
CcDisplayMonitorDBus *primary;
@@ -1059,6 +1060,9 @@ cc_display_config_dbus_equal (CcDisplayConfig *pself,
g_return_val_if_fail (pself, FALSE);
g_return_val_if_fail (pother, FALSE);
+ if (self->layout_mode != other->layout_mode)
+ return FALSE;
+
cc_display_config_dbus_ensure_non_offset_coords (self);
cc_display_config_dbus_ensure_non_offset_coords (other);
@@ -1215,6 +1219,13 @@ cc_display_config_dbus_layout_use_ui_scale (CcDisplayConfig *pself)
return self->layout_mode == CC_DISPLAY_LAYOUT_MODE_GLOBAL_UI_LOGICAL;
}
+static gint
+cc_display_config_dbus_get_legacy_ui_scale (CcDisplayConfig *pself)
+{
+ CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
+ return self->legacy_ui_scale;
+}
+
static gboolean
is_scaled_mode_allowed (CcDisplayConfigDBus *self,
CcDisplayMode *pmode,
@@ -1469,6 +1480,10 @@ cc_display_config_dbus_constructed (GObject *object)
{
g_variant_get (v, "b", &self->global_scale_required);
}
+ else if (g_str_equal (s, "legacy-ui-scaling-factor"))
+ {
+ g_variant_get (v, "i", &self->legacy_ui_scale);
+ }
else if (g_str_equal (s, "layout-mode"))
{
guint32 u = 0;
@@ -1565,6 +1580,7 @@ cc_display_config_dbus_class_init (CcDisplayConfigDBusClass *klass)
parent_class->is_scaled_mode_valid = cc_display_config_dbus_is_scaled_mode_valid;
parent_class->set_minimum_size = cc_display_config_dbus_set_minimum_size;
parent_class->layout_use_ui_scale = cc_display_config_dbus_layout_use_ui_scale;
+ parent_class->get_legacy_ui_scale = cc_display_config_dbus_get_legacy_ui_scale;
pspec = g_param_spec_variant ("state",
"GVariant",
diff --git a/panels/display/cc-display-config.c b/panels/display/cc-display-config.c
index 552a1a6..2ff5a06 100644
--- a/panels/display/cc-display-config.c
+++ b/panels/display/cc-display-config.c
@@ -17,10 +17,23 @@
*
*/
+#define MUTTER_SCHEMA "org.gnome.mutter"
+#define MUTTER_EXPERIMENTAL_FEATURES_KEY "experimental-features"
+#define MUTTER_FEATURE_FRACTIONAL_SCALING_X11 "x11-randr-fractional-scaling"
+#define MUTTER_FEATURE_FRACTIONAL_SCALING_WAYLAND "scale-monitor-framebuffer"
+
+#include <gdk/gdk.h>
#include <gio/gio.h>
#include <math.h>
#include "cc-display-config.h"
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+
static const double known_diagonals[] = {
12.1,
13.3,
@@ -419,6 +432,10 @@ cc_display_monitor_set_ui_info (CcDisplayMonitor *self, gint ui_number, gchar *u
struct _CcDisplayConfigPrivate {
GList *ui_sorted_monitors;
+
+ GSettings *mutter_settings;
+ gboolean fractional_scaling;
+ gboolean fractional_scaling_pending_disable;
};
typedef struct _CcDisplayConfigPrivate CcDisplayConfigPrivate;
@@ -426,12 +443,80 @@ G_DEFINE_TYPE_WITH_PRIVATE (CcDisplayConfig,
cc_display_config,
G_TYPE_OBJECT)
+static const char *
+get_fractional_scaling_key (void)
+{
+ GdkDisplay *display;
+
+ display = gdk_display_get_default ();
+
+#if defined(GDK_WINDOWING_X11)
+ if (GDK_IS_X11_DISPLAY (display))
+ return MUTTER_FEATURE_FRACTIONAL_SCALING_X11;
+#endif /* GDK_WINDOWING_X11 */
+#if defined(GDK_WINDOWING_WAYLAND)
+ if (GDK_IS_WAYLAND_DISPLAY (display))
+ return MUTTER_FEATURE_FRACTIONAL_SCALING_WAYLAND;
+#endif /* GDK_WINDOWING_WAYLAND */
+ g_return_val_if_reached (NULL);
+}
+
+static gboolean
+get_fractional_scaling_active (CcDisplayConfig *self)
+{
+ CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+ g_auto(GStrv) features = NULL;
+ const char *key = get_fractional_scaling_key ();
+
+ g_return_val_if_fail (key, FALSE);
+
+ features = g_settings_get_strv (priv->mutter_settings, MUTTER_EXPERIMENTAL_FEATURES_KEY);
+ return g_strv_contains ((const gchar **) features, key);
+}
+
+static void
+set_fractional_scaling_active (CcDisplayConfig *self,
+ gboolean enable)
+{
+ CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+ g_auto(GStrv) existing_features = NULL;
+ gboolean have_fractional_scaling = FALSE;
+ g_autoptr(GVariantBuilder) builder = NULL;
+ const char *key = get_fractional_scaling_key ();
+
+ /* Add or remove the fractional scaling feature from mutter */
+ existing_features = g_settings_get_strv (priv->mutter_settings,
+ MUTTER_EXPERIMENTAL_FEATURES_KEY);
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+ for (int i = 0; existing_features[i] != NULL; i++)
+ {
+ if (g_strcmp0 (existing_features[i], key) == 0)
+ {
+ if (enable)
+ have_fractional_scaling = TRUE;
+ else
+ continue;
+ }
+
+ g_variant_builder_add (builder, "s", existing_features[i]);
+ }
+ if (enable && !have_fractional_scaling && key)
+ g_variant_builder_add (builder, "s", key);
+
+ g_settings_set_value (priv->mutter_settings, MUTTER_EXPERIMENTAL_FEATURES_KEY,
+ g_variant_builder_end (builder));
+}
+
static void
cc_display_config_init (CcDisplayConfig *self)
{
CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
priv->ui_sorted_monitors = NULL;
+
+ /* No need to connect to the setting, as we'll get notified by mutter */
+ priv->mutter_settings = g_settings_new (MUTTER_SCHEMA);
+ priv->fractional_scaling = get_fractional_scaling_active (self);
}
static void
@@ -472,6 +557,7 @@ cc_display_config_finalize (GObject *object)
CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
g_list_free (priv->ui_sorted_monitors);
+ g_clear_object (&priv->mutter_settings);
G_OBJECT_CLASS (cc_display_config_parent_class)->finalize (object);
}
@@ -557,9 +643,16 @@ gboolean
cc_display_config_equal (CcDisplayConfig *self,
CcDisplayConfig *other)
{
+ CcDisplayConfigPrivate *spriv = cc_display_config_get_instance_private (self);
+ CcDisplayConfigPrivate *opriv = cc_display_config_get_instance_private (other);
+
g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), FALSE);
g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (other), FALSE);
+ if (spriv->fractional_scaling_pending_disable !=
+ opriv->fractional_scaling_pending_disable)
+ return FALSE;
+
return CC_DISPLAY_CONFIG_GET_CLASS (self)->equal (self, other);
}
@@ -567,6 +660,8 @@ gboolean
cc_display_config_apply (CcDisplayConfig *self,
GError **error)
{
+ CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
if (!CC_IS_DISPLAY_CONFIG (self))
{
g_warning ("Cannot apply invalid configuration");
@@ -577,6 +672,12 @@ cc_display_config_apply (CcDisplayConfig *self,
return FALSE;
}
+ if (priv->fractional_scaling_pending_disable)
+ {
+ set_fractional_scaling_active (self, FALSE);
+ priv->fractional_scaling_pending_disable = FALSE;
+ }
+
return CC_DISPLAY_CONFIG_GET_CLASS (self)->apply (self, error);
}
@@ -618,13 +719,31 @@ cc_display_config_set_minimum_size (CcDisplayConfig *self,
CC_DISPLAY_CONFIG_GET_CLASS (self)->set_minimum_size (self, width, height);
}
+gint
+cc_display_config_get_legacy_ui_scale (CcDisplayConfig *self)
+{
+ return CC_DISPLAY_CONFIG_GET_CLASS (self)->get_legacy_ui_scale (self);
+}
+
+static gboolean
+scale_value_is_fractional (double scale)
+{
+ return (int) scale != scale;
+}
+
gboolean
cc_display_config_is_scaled_mode_valid (CcDisplayConfig *self,
CcDisplayMode *mode,
double scale)
{
+ CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
g_return_val_if_fail (CC_IS_DISPLAY_CONFIG (self), FALSE);
g_return_val_if_fail (CC_IS_DISPLAY_MODE (mode), FALSE);
+
+ if (priv->fractional_scaling_pending_disable && scale_value_is_fractional (scale))
+ return FALSE;
+
return CC_DISPLAY_CONFIG_GET_CLASS (self)->is_scaled_mode_valid (self, mode, scale);
}
@@ -653,3 +772,121 @@ cc_display_config_get_maximum_scaling (CcDisplayConfig *self)
return max_scale;
}
+
+static gboolean
+set_monitors_scaling_to_preferred_integers (CcDisplayConfig *self)
+{
+ GList *l;
+ gboolean any_changed = FALSE;
+
+ for (l = cc_display_config_get_monitors (self); l; l = l->next)
+ {
+ CcDisplayMonitor *monitor = l->data;
+ gdouble monitor_scale = cc_display_monitor_get_scale (monitor);
+
+ if (scale_value_is_fractional (monitor_scale))
+ {
+ CcDisplayMode *preferred_mode;
+ double preferred_scale;
+ double *saved_scale;
+
+ preferred_mode = cc_display_monitor_get_preferred_mode (monitor);
+ preferred_scale = cc_display_mode_get_preferred_scale (preferred_mode);
+ cc_display_monitor_set_scale (monitor, preferred_scale);
+ any_changed = TRUE;
+
+ saved_scale = g_new (double, 1);
+ *saved_scale = monitor_scale;
+ g_object_set_data_full (G_OBJECT (monitor),
+ "previous-fractional-scale",
+ saved_scale, g_free);
+ }
+ else
+ {
+ g_signal_emit_by_name (monitor, "scale");
+ }
+ }
+
+ return any_changed;
+}
+
+static void
+reset_monitors_scaling_to_selected_values (CcDisplayConfig *self)
+{
+ GList *l;
+
+ for (l = cc_display_config_get_monitors (self); l; l = l->next)
+ {
+ CcDisplayMonitor *monitor = l->data;
+ gdouble *saved_scale;
+
+ saved_scale = g_object_get_data (G_OBJECT (monitor),
+ "previous-fractional-scale");
+
+ if (saved_scale)
+ {
+ cc_display_monitor_set_scale (monitor, *saved_scale);
+ g_object_set_data (G_OBJECT (monitor), "previous-fractional-scale", NULL);
+ }
+ else
+ {
+ g_signal_emit_by_name (monitor, "scale");
+ }
+ }
+}
+
+void
+cc_display_config_set_fractional_scaling (CcDisplayConfig *self,
+ gboolean enabled)
+{
+ CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
+ if (priv->fractional_scaling == enabled)
+ return;
+
+ priv->fractional_scaling = enabled;
+
+ if (priv->fractional_scaling)
+ {
+ if (priv->fractional_scaling_pending_disable)
+ {
+ priv->fractional_scaling_pending_disable = FALSE;
+ reset_monitors_scaling_to_selected_values (self);
+ }
+
+ if (!get_fractional_scaling_active (self))
+ set_fractional_scaling_active (self, enabled);
+ }
+ else
+ {
+ priv->fractional_scaling_pending_disable = TRUE;
+
+ if (!set_monitors_scaling_to_preferred_integers (self))
+ {
+ gboolean disable_now = FALSE;
+
+ if (cc_display_config_layout_use_ui_scale (self))
+ {
+ disable_now =
+ G_APPROX_VALUE (cc_display_config_get_legacy_ui_scale (self),
+ cc_display_config_get_maximum_scaling (self),
+ DBL_EPSILON);
+ }
+
+ if (disable_now)
+ {
+ priv->fractional_scaling_pending_disable = FALSE;
+ reset_monitors_scaling_to_selected_values (self);
+ set_fractional_scaling_active (self, enabled);
+ }
+ }
+ }
+}
+
+gboolean
+cc_display_config_get_fractional_scaling (CcDisplayConfig *self)
+{
+ CcDisplayConfigPrivate *priv = cc_display_config_get_instance_private (self);
+
+ return priv->fractional_scaling;
+}
diff --git a/panels/display/cc-display-config.h b/panels/display/cc-display-config.h
index 1361f16..4a1548e 100644
--- a/panels/display/cc-display-config.h
+++ b/panels/display/cc-display-config.h
@@ -161,6 +161,7 @@ struct _CcDisplayConfigClass
CcDisplayMode *mode,
double scale);
gboolean (*layout_use_ui_scale) (CcDisplayConfig *self);
+ gint (*get_legacy_ui_scale) (CcDisplayConfig *self);
};
@@ -188,8 +189,12 @@ gboolean cc_display_config_is_scaled_mode_valid (CcDisplayConfig
CcDisplayMode *mode,
double scale);
gboolean cc_display_config_layout_use_ui_scale (CcDisplayConfig *self);
+gint cc_display_config_get_legacy_ui_scale (CcDisplayConfig *self);
double cc_display_config_get_maximum_scaling (CcDisplayConfig *self);
+void cc_display_config_set_fractional_scaling (CcDisplayConfig *self,
+ gboolean enabled);
+gboolean cc_display_config_get_fractional_scaling (CcDisplayConfig *self);
const char* cc_display_monitor_get_display_name (CcDisplayMonitor *monitor);
gboolean cc_display_monitor_is_active (CcDisplayMonitor *monitor);
diff --git a/panels/display/cc-display-settings.c b/panels/display/cc-display-settings.c
index d793fcc..947335a 100644
--- a/panels/display/cc-display-settings.c
+++ b/panels/display/cc-display-settings.c
@@ -49,6 +49,8 @@ struct _CcDisplaySettings
GtkWidget *resolution_row;
GtkWidget *scale_bbox;
GtkWidget *scale_row;
+ GtkWidget *scale_fractional_row;
+ GtkWidget *scale_fractional_switch;
GtkWidget *underscanning_row;
GtkWidget *underscanning_switch;
};
@@ -71,7 +73,6 @@ static void on_scale_btn_active_changed_cb (GtkWidget *widget,
GParamSpec *pspec,
CcDisplaySettings *self);
-
static gboolean
should_show_rotation (CcDisplaySettings *self)
{
@@ -242,6 +243,7 @@ cc_display_settings_rebuild_ui (CcDisplaySettings *self)
gtk_widget_set_visible (self->refresh_rate_row, FALSE);
gtk_widget_set_visible (self->resolution_row, FALSE);
gtk_widget_set_visible (self->scale_row, FALSE);
+ gtk_widget_set_visible (self->scale_fractional_row, FALSE);
gtk_widget_set_visible (self->underscanning_row, FALSE);
return G_SOURCE_REMOVE;
@@ -429,6 +431,10 @@ cc_display_settings_rebuild_ui (CcDisplaySettings *self)
gtk_widget_set_visible (self->scale_row, buttons > 1);
+ gtk_widget_set_visible (self->scale_fractional_row, TRUE);
+ gtk_switch_set_active (GTK_SWITCH (self->scale_fractional_switch),
+ cc_display_config_get_fractional_scaling (self->config));
+
gtk_widget_set_visible (self->underscanning_row,
cc_display_monitor_supports_underscanning (self->selected_output) &&
!cc_display_config_is_cloning (self->config));
@@ -671,6 +677,8 @@ cc_display_settings_class_init (CcDisplaySettingsClass *klass)
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, resolution_row);
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_bbox);
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_row);
+ gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_fractional_row);
+ gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, scale_fractional_switch);
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, underscanning_row);
gtk_widget_class_bind_template_child (widget_class, CcDisplaySettings, underscanning_switch);
@@ -680,11 +688,29 @@ cc_display_settings_class_init (CcDisplaySettingsClass *klass)
gtk_widget_class_bind_template_callback (widget_class, on_underscanning_switch_active_changed_cb);
}
+static void
+on_scale_fractional_toggled (CcDisplaySettings *self)
+{
+ gboolean active;
+
+ active = gtk_switch_get_active (GTK_SWITCH (self->scale_fractional_switch));
+
+ if (self->config)
+ cc_display_config_set_fractional_scaling (self->config, active);
+
+ g_signal_emit_by_name (G_OBJECT (self), "updated", self->selected_output);
+}
+
static void
cc_display_settings_init (CcDisplaySettings *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
+ g_signal_connect_object (self->scale_fractional_switch,
+ "notify::active",
+ G_CALLBACK (on_scale_fractional_toggled),
+ self, G_CONNECT_SWAPPED);
+
gtk_list_box_set_header_func (GTK_LIST_BOX (self),
cc_list_box_update_header_func,
NULL, NULL);
diff --git a/panels/display/cc-display-settings.ui b/panels/display/cc-display-settings.ui
index 50ef951..cf8ca0a 100644
--- a/panels/display/cc-display-settings.ui
+++ b/panels/display/cc-display-settings.ui
@@ -68,5 +68,21 @@
</child>
</object>
</child>
+ <child>
+ <object class="HdyActionRow" id="scale_fractional_row">
+ <property name="width_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="title" translatable="yes" context="display setting">Fractional Scaling</property>
+ <property name="subtitle" translatable="yes" context="display setting">May increase power usage, lower speed, or reduce display sharpness.</property>
+ <child type="action">
+ <object class="GtkSwitch" id="scale_fractional_switch">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
</template>
</interface>