display: Adapt to new Mutter interface with scaling per mode

New Mutter GetCurrentState now provides a list of available scales, we
need to use these values in order to define an UI that shows them all.
This commit is contained in:
Marco Trevisan (Treviño) 2017-06-07 20:36:17 +08:00 committed by Rui Matos
parent a23aa64ec7
commit cca9663d87
5 changed files with 191 additions and 93 deletions

View file

@ -21,17 +21,17 @@
#include "cc-display-config-dbus.h"
#define MODE_FORMAT "(iiddu)"
#define MODE_FORMAT "(iiddadu)"
#define MODES_FORMAT "a" MODE_FORMAT
#define MONITOR_SPEC_FORMAT "(ssss)"
#define MONITOR_FORMAT "(" MONITOR_SPEC_FORMAT MODES_FORMAT "a{sv})"
#define MONITORS_FORMAT "a" MONITOR_FORMAT
#define LOGICAL_MONITOR_FORMAT "(iiduba" MONITOR_SPEC_FORMAT "a{sv})"
#define LOGICAL_MONITOR_MONITORS_FORMAT "a" MONITOR_SPEC_FORMAT
#define LOGICAL_MONITOR_FORMAT "(iidub" LOGICAL_MONITOR_MONITORS_FORMAT "a{sv})"
#define LOGICAL_MONITORS_FORMAT "a" LOGICAL_MONITOR_FORMAT
#define CURRENT_STATE_FORMAT "(u" MONITORS_FORMAT LOGICAL_MONITORS_FORMAT "ad" "a{sv})"
#define CURRENT_STATE_FORMAT "(u" MONITORS_FORMAT LOGICAL_MONITORS_FORMAT "a{sv})"
typedef enum _CcDisplayModeFlags
{
@ -47,6 +47,7 @@ struct _CcDisplayModeDBus
int height;
double refresh_rate;
double preferred_scale;
GArray *supported_scales;
guint32 flags;
};
@ -80,6 +81,36 @@ cc_display_mode_dbus_get_resolution (CcDisplayMode *pself,
*h = self->height;
}
static const double *
cc_display_mode_dbus_get_supported_scales (CcDisplayMode *pself)
{
CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
return (const double *) self->supported_scales->data;
}
static double
cc_display_mode_dbus_get_preferred_scale (CcDisplayMode *pself)
{
CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
return self->preferred_scale;
}
static gboolean
cc_display_mode_dbus_is_supported_scale (CcDisplayMode *pself,
double scale)
{
CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (pself);
guint i;
for (i = 0; i < self->supported_scales->len; i++)
if (g_array_index (self->supported_scales, double, i) == scale)
return TRUE;
return FALSE;
}
static gboolean
cc_display_mode_dbus_is_interlaced (CcDisplayMode *pself)
{
@ -106,11 +137,16 @@ cc_display_mode_dbus_get_freq_f (CcDisplayMode *pself)
static void
cc_display_mode_dbus_init (CcDisplayModeDBus *self)
{
self->supported_scales = g_array_new (TRUE, TRUE, sizeof (double));
}
static void
cc_display_mode_dbus_finalize (GObject *object)
{
CcDisplayModeDBus *self = CC_DISPLAY_MODE_DBUS (object);
g_array_free (self->supported_scales, TRUE);
G_OBJECT_CLASS (cc_display_mode_dbus_parent_class)->finalize (object);
}
@ -123,6 +159,8 @@ cc_display_mode_dbus_class_init (CcDisplayModeDBusClass *klass)
gobject_class->finalize = cc_display_mode_dbus_finalize;
parent_class->get_resolution = cc_display_mode_dbus_get_resolution;
parent_class->get_supported_scales = cc_display_mode_dbus_get_supported_scales;
parent_class->get_preferred_scale = cc_display_mode_dbus_get_preferred_scale;
parent_class->is_interlaced = cc_display_mode_dbus_is_interlaced;
parent_class->get_freq = cc_display_mode_dbus_get_freq;
parent_class->get_freq_f = cc_display_mode_dbus_get_freq_f;
@ -131,6 +169,8 @@ cc_display_mode_dbus_class_init (CcDisplayModeDBusClass *klass)
static CcDisplayModeDBus *
cc_display_mode_dbus_new (GVariant *variant)
{
double d;
GVariantIter *scales_iter;
CcDisplayModeDBus *self = g_object_new (CC_TYPE_DISPLAY_MODE_DBUS, NULL);
g_variant_get (variant, MODE_FORMAT,
@ -138,8 +178,14 @@ cc_display_mode_dbus_new (GVariant *variant)
&self->height,
&self->refresh_rate,
&self->preferred_scale,
&scales_iter,
&self->flags);
while (g_variant_iter_next (scales_iter, "d", &d))
g_array_append_val (self->supported_scales, d);
g_variant_iter_free (scales_iter);
return self;
}
@ -262,9 +308,6 @@ static void
cc_display_config_dbus_ensure_gapless (CcDisplayConfigDBus *self);
static void
cc_display_config_dbus_make_linear (CcDisplayConfigDBus *self);
static gboolean
cc_display_config_dbus_is_supported_scale (CcDisplayConfigDBus *self,
double scale);
static const char *
@ -591,6 +634,9 @@ cc_display_monitor_dbus_set_mode (CcDisplayMonitor *pself,
existing layout here. */
if (w1 != w2 || h1 != h2)
cc_display_config_dbus_make_linear (self->config);
if (!cc_display_mode_dbus_is_supported_scale (mode, cc_display_monitor_get_scale (pself)))
cc_display_monitor_set_scale (pself, cc_display_mode_get_preferred_scale (mode));
}
static void
@ -623,7 +669,10 @@ cc_display_monitor_dbus_set_scale (CcDisplayMonitor *pself,
{
CcDisplayMonitorDBus *self = CC_DISPLAY_MONITOR_DBUS (pself);
if (!cc_display_config_dbus_is_supported_scale (self->config, scale))
if (!self->current_mode)
return;
if (!cc_display_mode_dbus_is_supported_scale (self->current_mode, scale))
return;
if (!self->logical_monitor)
@ -812,8 +861,6 @@ struct _CcDisplayConfigDBus
gboolean supports_changing_layout_mode;
CcDisplayLayoutMode layout_mode;
GArray *supported_scales;
GList *monitors;
CcDisplayMonitorDBus *primary;
@ -1115,14 +1162,6 @@ cc_display_config_dbus_apply (CcDisplayConfig *pself,
return config_apply (self, CC_DISPLAY_CONFIG_METHOD_PERSISTENT, error);
}
static const double *
cc_display_config_dbus_get_supported_scales (CcDisplayConfig *pself)
{
CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (pself);
return (const double *) self->supported_scales->data;
}
static gboolean
cc_display_config_dbus_is_layout_logical (CcDisplayConfig *pself)
{
@ -1138,7 +1177,6 @@ cc_display_config_dbus_init (CcDisplayConfigDBus *self)
self->supports_mirroring = TRUE;
self->supports_changing_layout_mode = FALSE;
self->layout_mode = CC_DISPLAY_LAYOUT_MODE_LOGICAL;
self->supported_scales = g_array_new (TRUE, TRUE, sizeof (double));
self->logical_monitors = g_hash_table_new (NULL, NULL);
}
@ -1265,9 +1303,7 @@ cc_display_config_dbus_constructed (GObject *object)
CcDisplayConfigDBus *self = CC_DISPLAY_CONFIG_DBUS (object);
GVariantIter *monitors;
GVariantIter *logical_monitors;
GVariantIter *scales;
GVariantIter *props;
double d;
const char *s;
GVariant *v;
@ -1276,12 +1312,8 @@ cc_display_config_dbus_constructed (GObject *object)
&self->serial,
&monitors,
&logical_monitors,
&scales,
&props);
while (g_variant_iter_next (scales, "d", &d))
g_array_append_val (self->supported_scales, d);
while (g_variant_iter_next (props, "{&sv}", &s, &v))
{
if (g_str_equal (s, "supports-mirroring"))
@ -1308,7 +1340,6 @@ cc_display_config_dbus_constructed (GObject *object)
g_variant_iter_free (monitors);
g_variant_iter_free (logical_monitors);
g_variant_iter_free (scales);
g_variant_iter_free (props);
G_OBJECT_CLASS (cc_display_config_dbus_parent_class)->constructed (object);
@ -1364,7 +1395,6 @@ cc_display_config_dbus_finalize (GObject *object)
g_clear_pointer (&self->state, g_variant_unref);
g_clear_object (&self->connection);
g_array_free (self->supported_scales, TRUE);
g_list_foreach (self->monitors, (GFunc) g_object_unref, NULL);
g_clear_pointer (&self->monitors, g_list_free);
g_clear_pointer (&self->logical_monitors, g_hash_table_destroy);
@ -1392,7 +1422,6 @@ cc_display_config_dbus_class_init (CcDisplayConfigDBusClass *klass)
parent_class->is_cloning = cc_display_config_dbus_is_cloning;
parent_class->set_cloning = cc_display_config_dbus_set_cloning;
parent_class->get_cloning_modes = cc_display_config_dbus_get_cloning_modes;
parent_class->get_supported_scales = cc_display_config_dbus_get_supported_scales;
parent_class->is_layout_logical = cc_display_config_dbus_is_layout_logical;
pspec = g_param_spec_variant ("state",
@ -1632,14 +1661,3 @@ cc_display_config_dbus_make_linear (CcDisplayConfigDBus *self)
g_list_free (logical_monitors);
}
static gboolean
cc_display_config_dbus_is_supported_scale (CcDisplayConfigDBus *self,
double scale)
{
guint i;
for (i = 0; i < self->supported_scales->len; i++)
if (g_array_index (self->supported_scales, double, i) == scale)
return TRUE;
return FALSE;
}

View file

@ -46,6 +46,20 @@ cc_display_mode_rr_get_resolution (CcDisplayMode *pself,
*h = gnome_rr_mode_get_height (self->rr_mode);
}
static double rr_supported_scales[] = { 1.0, 0.0 };
static const double *
cc_display_mode_rr_get_supported_scales (CcDisplayMode *pself)
{
return rr_supported_scales;
}
static double
cc_display_mode_rr_get_preferred_scale (CcDisplayMode *pself)
{
return rr_supported_scales[0];
}
static gboolean
cc_display_mode_rr_is_interlaced (CcDisplayMode *pself)
{
@ -90,6 +104,8 @@ cc_display_mode_rr_class_init (CcDisplayModeRRClass *klass)
gobject_class->finalize = cc_display_mode_rr_finalize;
parent_class->get_resolution = cc_display_mode_rr_get_resolution;
parent_class->get_supported_scales = cc_display_mode_rr_get_supported_scales;
parent_class->get_preferred_scale = cc_display_mode_rr_get_preferred_scale;
parent_class->is_interlaced = cc_display_mode_rr_is_interlaced;
parent_class->get_freq = cc_display_mode_rr_get_freq;
parent_class->get_freq_f = cc_display_mode_rr_get_freq_f;
@ -339,7 +355,7 @@ cc_display_monitor_rr_set_position (CcDisplayMonitor *pself,
static double
cc_display_monitor_rr_get_scale (CcDisplayMonitor *pself)
{
return 1.0;
return rr_supported_scales[0];
}
static void
@ -429,9 +445,6 @@ cc_display_monitor_rr_new (GnomeRROutput *output,
return CC_DISPLAY_MONITOR (self);
}
static double rr_supported_scales[] = { 1.0, 0.0 };
struct _CcDisplayConfigRR
{
CcDisplayConfig parent_instance;
@ -556,12 +569,6 @@ cc_display_config_rr_get_cloning_modes (CcDisplayConfig *pself)
return self->clone_modes;
}
static const double *
cc_display_config_rr_get_supported_scales (CcDisplayConfig *pself)
{
return rr_supported_scales;
}
static gboolean
cc_display_config_rr_is_layout_logical (CcDisplayConfig *pself)
{
@ -687,7 +694,6 @@ cc_display_config_rr_class_init (CcDisplayConfigRRClass *klass)
parent_class->is_cloning = cc_display_config_rr_is_cloning;
parent_class->set_cloning = cc_display_config_rr_set_cloning;
parent_class->get_cloning_modes = cc_display_config_rr_get_cloning_modes;
parent_class->get_supported_scales = cc_display_config_rr_get_supported_scales;
parent_class->is_layout_logical = cc_display_config_rr_is_layout_logical;
pspec = g_param_spec_object ("gnome-rr-screen",

View file

@ -39,6 +39,18 @@ cc_display_mode_get_resolution (CcDisplayMode *self, int *w, int *h)
return CC_DISPLAY_MODE_GET_CLASS (self)->get_resolution (self, w, h);
}
const double *
cc_display_mode_get_supported_scales (CcDisplayMode *self)
{
return CC_DISPLAY_MODE_GET_CLASS (self)->get_supported_scales (self);
}
double
cc_display_mode_get_preferred_scale (CcDisplayMode *self)
{
return CC_DISPLAY_MODE_GET_CLASS (self)->get_preferred_scale (self);
}
gboolean
cc_display_mode_is_interlaced (CcDisplayMode *self)
{
@ -272,12 +284,6 @@ cc_display_config_get_cloning_modes (CcDisplayConfig *self)
return CC_DISPLAY_CONFIG_GET_CLASS (self)->get_cloning_modes (self);
}
const double *
cc_display_config_get_supported_scales (CcDisplayConfig *self)
{
return CC_DISPLAY_CONFIG_GET_CLASS (self)->get_supported_scales (self);
}
gboolean
cc_display_config_is_layout_logical (CcDisplayConfig *self)
{

View file

@ -79,6 +79,8 @@ struct _CcDisplayModeClass
GObjectClass parent_class;
void (*get_resolution) (CcDisplayMode *self, int *w, int *h);
const double * (*get_supported_scales) (CcDisplayMode *self);
double (*get_preferred_scale) (CcDisplayMode *self);
gboolean (*is_interlaced) (CcDisplayMode *self);
int (*get_freq) (CcDisplayMode *self);
double (*get_freq_f) (CcDisplayMode *self);
@ -134,7 +136,6 @@ struct _CcDisplayConfigClass
gboolean (*is_cloning) (CcDisplayConfig *self);
void (*set_cloning) (CcDisplayConfig *self, gboolean clone);
GList * (*get_cloning_modes) (CcDisplayConfig *self);
const double * (*get_supported_scales) (CcDisplayConfig *self);
gboolean (*is_layout_logical) (CcDisplayConfig *self);
};
@ -147,7 +148,6 @@ gboolean cc_display_config_apply (CcDisplayConfig *config, GError **error);
gboolean cc_display_config_is_cloning (CcDisplayConfig *config);
void cc_display_config_set_cloning (CcDisplayConfig *config, gboolean clone);
GList *cc_display_config_get_cloning_modes (CcDisplayConfig *config);
const double *cc_display_config_get_supported_scales (CcDisplayConfig *self);
gboolean cc_display_config_is_layout_logical (CcDisplayConfig *self);
const char * cc_display_monitor_get_display_name (CcDisplayMonitor *monitor);
@ -186,11 +186,10 @@ void cc_display_monitor_set_position (CcDisplayMonitor *monitor,
int x, int y);
void cc_display_mode_get_resolution (CcDisplayMode *mode,
int *width,
int *height);
void cc_display_mode_get_dimensions (CcDisplayMode *mode,
int *width,
int *hegiht);
int *height);
const double *cc_display_mode_get_supported_scales (CcDisplayMode *self);
double cc_display_mode_get_preferred_scale (CcDisplayMode *self);
gboolean cc_display_mode_is_interlaced (CcDisplayMode *mode);
int cc_display_mode_get_freq (CcDisplayMode *mode);
double cc_display_mode_get_freq_f (CcDisplayMode *mode);

View file

@ -82,6 +82,7 @@ struct _CcDisplayPanelPrivate
GtkWidget *arrange_button;
GtkWidget *res_combo;
GtkWidget *freq_combo;
GtkWidget *scale_slider;
GHashTable *res_freqs;
GtkWidget *scaling_switch;
GtkWidget *rotate_left_button;
@ -1698,6 +1699,72 @@ setup_frequency_combo_box (CcDisplayPanel *panel,
gtk_combo_box_set_active (GTK_COMBO_BOX (priv->freq_combo), 0);
}
static guint
n_supported_scales (CcDisplayMode *mode)
{
const double *scales = cc_display_mode_get_supported_scales (mode);
guint n = 0;
while (scales[n] != 0.0)
n++;
return n;
}
static void
setup_scaling_slider (CcDisplayPanel *panel,
CcDisplayMode *resolution_mode)
{
CcDisplayPanelPrivate *priv = panel->priv;
guint i;
guint n;
const double *scales;
scales = cc_display_mode_get_supported_scales (resolution_mode);
n = n_supported_scales (resolution_mode);
if (n > 0)
{
GtkAdjustment *adj;
double current_scale;
int current_index = -1;
current_scale = cc_display_monitor_get_scale (priv->current_output);
adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale_slider));
gtk_scale_clear_marks (GTK_SCALE (priv->scale_slider));
gtk_adjustment_set_step_increment (adj, 1);
gtk_adjustment_set_lower (adj, 0);
gtk_adjustment_set_upper (adj, n-1);
gtk_scale_set_digits (GTK_SCALE (priv->scale_slider), 0);
for (i = 0; i < n; ++i)
{
double rounded_scale = round (scales[i] * 10) / 10;
double integral;
double fractional = modf (rounded_scale, &integral);
if (scales[i] == current_scale || (current_index < 0 && scales[i] == 1.0))
current_index = i;
if (fractional != 0 && (fractional != 0.5 || integral > 0))
continue;
gchar *s = g_strdup_printf ("%.2lg×", scales[i]);
gtk_scale_add_mark (GTK_SCALE (priv->scale_slider), i, GTK_POS_TOP, s);
g_free (s);
}
gtk_widget_show (priv->scale_slider);
gtk_range_set_value (GTK_RANGE (priv->scale_slider), current_index);
}
else
{
gtk_widget_hide (priv->scale_slider);
}
}
static void
free_mode_list (gpointer key,
gpointer value,
@ -1782,6 +1849,7 @@ setup_resolution_combo_box (CcDisplayPanel *panel,
gtk_combo_box_set_active (GTK_COMBO_BOX (priv->res_combo), 0);
setup_frequency_combo_box (panel, current_mode);
setup_scaling_slider (panel, current_mode);
}
@ -1988,6 +2056,7 @@ res_combo_changed (GtkComboBox *combo,
update_apply_button (panel);
setup_frequency_combo_box (panel, mode);
setup_scaling_slider (panel, mode);
}
}
@ -2041,16 +2110,17 @@ underscan_switch_toggled (CcDisplayPanel *panel)
update_apply_button (panel);
}
static guint
n_supported_scales (CcDisplayConfig *config)
static double
scale_slider_get_selected_scale (CcDisplayPanel *panel)
{
const double *scales = cc_display_config_get_supported_scales (config);
guint n = 0;
CcDisplayPanelPrivate *priv = panel->priv;
CcDisplayMode *mode = cc_display_monitor_get_mode (priv->current_output);
const double *scales = cc_display_mode_get_supported_scales (mode);
int selected = gtk_range_get_value (GTK_RANGE (priv->scale_slider));
while (scales[n] != 0.0)
n++;
g_return_val_if_fail (selected < n_supported_scales (mode), 1.0);
return n;
return scales[selected];
}
static void
@ -2058,10 +2128,18 @@ scale_slider_changed (GtkRange *slider,
CcDisplayPanel *panel)
{
cc_display_monitor_set_scale (panel->priv->current_output,
gtk_range_get_value (slider));
scale_slider_get_selected_scale (panel));
update_apply_button (panel);
}
static char *
scale_slider_format_value (GtkScale *slider,
double value,
CcDisplayPanel *panel)
{
return g_strdup_printf ("%.3g", scale_slider_get_selected_scale (panel));
}
static void
show_setup_dialog (CcDisplayPanel *panel)
{
@ -2298,31 +2376,22 @@ show_setup_dialog (CcDisplayPanel *panel)
grid_pos++;
/* scale */
if (n_supported_scales (priv->current_config) > 1)
{
GtkWidget *slider;
const double *scales = cc_display_config_get_supported_scales (priv->current_config);
guint n = n_supported_scales (priv->current_config);
guint i = 0;
priv->scale_slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, NULL);
gtk_widget_set_no_show_all (priv->scale_slider, TRUE);
slider = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL,
scales[0], scales[n - 1],
scales[1] - scales[0]);
gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE);
gtk_scale_set_has_origin (GTK_SCALE (slider), FALSE);
for (i = 0; i < n; i++)
{
gchar *s = g_strdup_printf ("%.1lg×", scales[i]);
gtk_scale_add_mark (GTK_SCALE (slider), scales[i], GTK_POS_TOP, s);
g_free (s);
}
gtk_range_set_value (GTK_RANGE (slider), cc_display_monitor_get_scale (priv->current_output));
g_signal_connect (slider, "value-changed", G_CALLBACK (scale_slider_changed), panel);
g_signal_connect (priv->scale_slider, "format-value",
G_CALLBACK (scale_slider_format_value), panel);
g_signal_connect (priv->scale_slider, "value-changed",
G_CALLBACK (scale_slider_changed), panel);
gtk_grid_attach (GTK_GRID (priv->config_grid), slider, 1, grid_pos, 1, 1);
gtk_widget_set_halign (priv->freq_combo, GTK_ALIGN_CENTER);
grid_pos++;
}
gtk_scale_set_draw_value (GTK_SCALE (priv->scale_slider), TRUE);
gtk_range_set_round_digits (GTK_RANGE (priv->scale_slider), 2);
gtk_scale_set_value_pos (GTK_SCALE (priv->scale_slider), GTK_POS_BOTTOM);
gtk_scale_set_has_origin (GTK_SCALE (priv->scale_slider), FALSE);
gtk_grid_attach (GTK_GRID (priv->config_grid),
priv->scale_slider, 1, grid_pos, 1, 1);
gtk_widget_set_halign (priv->freq_combo, GTK_ALIGN_CENTER);
grid_pos++;
was_clone = clone = cc_display_config_is_cloning (priv->current_config);
primary = cc_display_monitor_is_primary (priv->current_output);