summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Kareh <[email protected]>2018-02-01 00:14:38 -0500
committerraveit65 <[email protected]>2018-02-06 17:19:21 +0100
commit16137a4d4c51fae1d577ea4c534af4a89f5c1558 (patch)
treec978d35add4cc9869b70e8404cefecc40201ad89
parentddc7f0f6d90fa6f425c02456091d080f572a72ba (diff)
downloadmate-settings-daemon-16137a4d4c51fae1d577ea4c534af4a89f5c1558.tar.bz2
mate-settings-daemon-16137a4d4c51fae1d577ea4c534af4a89f5c1558.tar.xz
Add HiDPI configuration in XSettings
This change allows for Xft/Gdk settings to be changed dynamically for the scaling factor and font DPI. It also has an optional auto-detection algorithm for the most appropriate settings to use for different screen sizes and resolutions. The auto-detect is re-triggered whenever the screen size changes.
-rw-r--r--plugins/xsettings/msd-xsettings-manager.c135
1 files changed, 116 insertions, 19 deletions
diff --git a/plugins/xsettings/msd-xsettings-manager.c b/plugins/xsettings/msd-xsettings-manager.c
index 9105088..d12b23e 100644
--- a/plugins/xsettings/msd-xsettings-manager.c
+++ b/plugins/xsettings/msd-xsettings-manager.c
@@ -52,6 +52,7 @@
#define CURSOR_THEME_KEY "cursor-theme"
#define CURSOR_SIZE_KEY "cursor-size"
+#define SCALING_FACTOR_KEY "window-scaling-factor"
#define FONT_RENDER_SCHEMA "org.mate.font-rendering"
#define FONT_ANTIALIASING_KEY "antialiasing"
@@ -73,6 +74,14 @@
#define DPI_LOW_REASONABLE_VALUE 50
#define DPI_HIGH_REASONABLE_VALUE 500
+/* The minimum resolution at which we turn on a window-scale of 2 */
+#define HIDPI_LIMIT (DPI_FALLBACK * 2)
+
+/* The minimum screen height at which we turn on a window-scale of 2;
+ * below this there just isn't enough vertical real estate for GNOME
+ * apps to work, and it's better to just be tiny */
+#define HIDPI_MIN_HEIGHT 1500
+
typedef struct _TranslationEntry TranslationEntry;
typedef void (* TranslationFunc) (MateXSettingsManager *manager,
TranslationEntry *trans,
@@ -92,6 +101,7 @@ struct MateXSettingsManagerPrivate
GHashTable *gsettings;
GSettings *gsettings_font;
fontconfig_monitor_handle_t *fontconfig_handle;
+ gint window_scale;
};
#define MSD_XSETTINGS_ERROR msd_xsettings_error_quark ()
@@ -213,6 +223,70 @@ static TranslationEntry translations [] = {
{ SOUND_SCHEMA, "input-feedback-sounds", "Net/EnableInputFeedbackSounds", translate_bool_int }
};
+/* Auto-detect the most appropriate scale factor for the primary monitor.
+ * A lot of this code is shamelessly copied and adapted from Linux Mint/Cinnamon.
+ */
+static int
+get_window_scale_auto ()
+{
+ GdkDisplay *display;
+ GdkMonitor *monitor;
+ GdkRectangle rect;
+ int width_mm, height_mm;
+ int monitor_scale, window_scale;
+
+ display = gdk_display_get_default ();
+ monitor = gdk_display_get_primary_monitor (display);
+
+ /* Use current value as the default */
+ window_scale = 1;
+
+ gdk_monitor_get_geometry (monitor, &rect);
+ width_mm = gdk_monitor_get_width_mm (monitor);
+ height_mm = gdk_monitor_get_height_mm (monitor);
+ monitor_scale = gdk_monitor_get_scale_factor (monitor);
+
+ if (rect.height * monitor_scale < HIDPI_MIN_HEIGHT)
+ return 1;
+
+ /* Some monitors/TV encode the aspect ratio (16/9 or 16/10) instead of the physical size */
+ if ((width_mm == 160 && height_mm == 90) ||
+ (width_mm == 160 && height_mm == 100) ||
+ (width_mm == 16 && height_mm == 9) ||
+ (width_mm == 16 && height_mm == 10))
+ return 1;
+
+ if (width_mm > 0 && height_mm > 0) {
+ double dpi_x, dpi_y;
+
+ dpi_x = (double)rect.width * monitor_scale / (width_mm / 25.4);
+ dpi_y = (double)rect.height * monitor_scale / (height_mm / 25.4);
+ /* We don't completely trust these values so both must be high, and never pick
+ * higher ratio than 2 automatically */
+ if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT)
+ window_scale = 2;
+ }
+
+ return window_scale;
+}
+
+static int
+get_window_scale (MateXSettingsManager *manager)
+{
+ GSettings *gsettings;
+ gint scale;
+
+ /* Get scale factor from gsettings */
+ gsettings = g_hash_table_lookup (manager->priv->gsettings, INTERFACE_SCHEMA);
+ scale = g_settings_get_int (gsettings, SCALING_FACTOR_KEY);
+
+ /* Auto-detect */
+ if (scale == 0)
+ scale = get_window_scale_auto ();
+
+ return scale;
+}
+
static double
dpi_from_pixels_and_mm (int pixels,
int mm)
@@ -232,7 +306,6 @@ get_dpi_from_x_server (void)
{
GdkScreen *screen;
double dpi;
- gint scale;
screen = gdk_screen_get_default ();
if (screen != NULL) {
@@ -255,21 +328,15 @@ get_dpi_from_x_server (void)
dpi = DPI_FALLBACK;
}
-
- scale = gdk_window_get_scale_factor (gdk_screen_get_root_window (screen));
- if (scale)
- dpi = dpi * scale;
-
return dpi;
}
static double
-get_dpi_from_gsettings_or_x_server (GSettings *gsettings)
+get_dpi_from_gsettings_or_x_server (GSettings *gsettings, gint scale)
{
- double value;
double dpi;
- value = g_settings_get_double (gsettings, FONT_DPI_KEY);
+ dpi = g_settings_get_double (gsettings, FONT_DPI_KEY);
/* If the user has ever set the DPI preference in GSettings, we use that.
* Otherwise, we see if the X server reports a reasonable DPI value: some X
@@ -277,11 +344,11 @@ get_dpi_from_gsettings_or_x_server (GSettings *gsettings)
* fonts which are unusable.
*/
- if (value != 0) {
- dpi = value;
- } else {
+ if (dpi == 0)
dpi = get_dpi_from_x_server ();
- }
+
+ dpi *= (double)scale;
+ dpi = CLAMP(dpi, DPI_LOW_REASONABLE_VALUE, DPI_HIGH_REASONABLE_VALUE);
return dpi;
}
@@ -290,7 +357,9 @@ typedef struct
{
gboolean antialias;
gboolean hinting;
+ int window_scale;
int dpi;
+ int scaled_dpi;
char *cursor_theme;
int cursor_size;
const char *rgba;
@@ -307,7 +376,6 @@ xft_settings_get (MateXSettingsManager *manager,
MateXftSettings *settings)
{
GSettings *mouse_gsettings;
- GdkScreen *screen;
char *antialiasing;
char *hinting;
char *rgba_order;
@@ -315,22 +383,25 @@ xft_settings_get (MateXSettingsManager *manager,
gint scale;
mouse_gsettings = g_hash_table_lookup (manager->priv->gsettings, MOUSE_SCHEMA);
- screen = gdk_screen_get_default();
antialiasing = g_settings_get_string (manager->priv->gsettings_font, FONT_ANTIALIASING_KEY);
hinting = g_settings_get_string (manager->priv->gsettings_font, FONT_HINTING_KEY);
rgba_order = g_settings_get_string (manager->priv->gsettings_font, FONT_RGBA_ORDER_KEY);
- dpi = get_dpi_from_gsettings_or_x_server (manager->priv->gsettings_font);
- scale = gdk_window_get_scale_factor (gdk_screen_get_root_window (screen));
+ scale = get_window_scale (manager);
+ dpi = get_dpi_from_gsettings_or_x_server (manager->priv->gsettings_font, scale);
settings->antialias = TRUE;
settings->hinting = TRUE;
settings->hintstyle = "hintslight";
- settings->dpi = dpi * 1024; /* Xft wants 1/1024ths of an inch */
+ settings->window_scale = scale;
+ settings->dpi = dpi / scale * 1024; /* Xft wants 1/1024ths of an inch */
+ settings->scaled_dpi = dpi * 1024;
settings->cursor_theme = g_settings_get_string (mouse_gsettings, CURSOR_THEME_KEY);
settings->cursor_size = scale * g_settings_get_int (mouse_gsettings, CURSOR_SIZE_KEY);
settings->rgba = "rgb";
+ manager->priv->window_scale = scale;
+
if (rgba_order) {
int i;
gboolean found = FALSE;
@@ -404,7 +475,9 @@ xft_settings_set_xsettings (MateXSettingsManager *manager,
xsettings_manager_set_int (manager->priv->managers [i], "Xft/Antialias", settings->antialias);
xsettings_manager_set_int (manager->priv->managers [i], "Xft/Hinting", settings->hinting);
xsettings_manager_set_string (manager->priv->managers [i], "Xft/HintStyle", settings->hintstyle);
- xsettings_manager_set_int (manager->priv->managers [i], "Xft/DPI", settings->dpi);
+ xsettings_manager_set_int (manager->priv->managers [i], "Gdk/WindowScalingFactor", settings->window_scale);
+ xsettings_manager_set_int (manager->priv->managers [i], "Gdk/UnscaledDPI", settings->dpi);
+ xsettings_manager_set_int (manager->priv->managers [i], "Xft/DPI", settings->scaled_dpi);
xsettings_manager_set_string (manager->priv->managers [i], "Xft/RGBA", settings->rgba);
xsettings_manager_set_string (manager->priv->managers [i], "Xft/lcdfilter",
g_str_equal (settings->rgba, "rgb") ? "lcddefault" : "none");
@@ -508,6 +581,23 @@ update_xft_settings (MateXSettingsManager *manager)
}
static void
+screen_callback (GdkScreen *screen,
+ MateXSettingsManager *manager)
+{
+ int i;
+ int new_scale = get_window_scale (manager);
+
+ if (manager->priv->window_scale == new_scale)
+ return;
+
+ update_xft_settings (manager);
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_notify (manager->priv->managers [i]);
+ }
+}
+
+static void
xft_callback (GSettings *gsettings,
const gchar *key,
MateXSettingsManager *manager)
@@ -609,6 +699,7 @@ xsettings_callback (GSettings *gsettings,
GVariant *value;
if (g_str_equal (key, CURSOR_THEME_KEY) ||
+ g_str_equal (key, SCALING_FACTOR_KEY) ||
g_str_equal (key, CURSOR_SIZE_KEY)) {
xft_callback (NULL, key, manager);
return;
@@ -692,6 +783,7 @@ mate_xsettings_manager_start (MateXSettingsManager *manager,
{
guint i;
GList *list, *l;
+ GdkScreen *screen;
g_debug ("Starting xsettings manager");
mate_settings_profile_start (NULL);
@@ -718,6 +810,7 @@ mate_xsettings_manager_start (MateXSettingsManager *manager,
g_signal_connect_object (G_OBJECT (l->data), "changed",
G_CALLBACK (xsettings_callback), manager, 0);
}
+
g_list_free (list);
for (i = 0; i < G_N_ELEMENTS (translations); i++) {
@@ -738,6 +831,10 @@ mate_xsettings_manager_start (MateXSettingsManager *manager,
g_variant_unref (val);
}
+ /* Detect changes in screen resolution */
+ screen = gdk_screen_get_default();
+ g_signal_connect(screen, "size-changed", G_CALLBACK (screen_callback), manager);
+
manager->priv->gsettings_font = g_settings_new (FONT_RENDER_SCHEMA);
g_signal_connect (manager->priv->gsettings_font, "changed", G_CALLBACK (xft_callback), manager);
update_xft_settings (manager);