wayland: Support the settings portal
Under Wayland, we are currently directly using GSettings for desktop settings. But in a sandbox, we may not have access to dconf, so this may fail. Use the new settings portal instead.
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
#include "gdkmonitor-wayland.h"
|
||||
#include "gdkwayland.h"
|
||||
#include "gdkprivate-wayland.h"
|
||||
#include "gdk-private.h"
|
||||
|
||||
#include "wm-button-layout-translation.h"
|
||||
|
||||
@@ -71,6 +72,7 @@ struct _GdkWaylandScreen
|
||||
GHashTable *settings;
|
||||
GsdXftSettings xft_settings;
|
||||
GsdExtSettings dbus_settings;
|
||||
GDBusProxy *settings_portal;
|
||||
|
||||
GDBusProxy *dbus_proxy;
|
||||
GCancellable *dbus_cancellable;
|
||||
@@ -126,7 +128,10 @@ gdk_wayland_screen_finalize (GObject *object)
|
||||
|
||||
g_object_unref (screen_wayland->visual);
|
||||
|
||||
g_hash_table_destroy (screen_wayland->settings);
|
||||
if (screen_wayland->settings)
|
||||
g_hash_table_destroy (screen_wayland->settings);
|
||||
|
||||
g_clear_object (&screen_wayland->settings_portal);
|
||||
|
||||
g_free (screen_wayland->dbus_settings.modules);
|
||||
|
||||
@@ -238,6 +243,19 @@ typedef enum
|
||||
GSD_FONT_ANTIALIASING_MODE_RGBA
|
||||
} GsdFontAntialiasingMode;
|
||||
|
||||
static int
|
||||
get_antialiasing (const char *s)
|
||||
{
|
||||
const char *names[] = { "none", "grayscale", "rgba" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
if (strcmp (s, names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSD_FONT_HINTING_NONE,
|
||||
@@ -246,6 +264,19 @@ typedef enum
|
||||
GSD_FONT_HINTING_FULL
|
||||
} GsdFontHinting;
|
||||
|
||||
static int
|
||||
get_hinting (const char *s)
|
||||
{
|
||||
const char *names[] = { "none", "slight", "medium", "full" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
if (strcmp (s, names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSD_FONT_RGBA_ORDER_RGBA,
|
||||
@@ -255,6 +286,19 @@ typedef enum
|
||||
GSD_FONT_RGBA_ORDER_VBGR
|
||||
} GsdFontRgbaOrder;
|
||||
|
||||
static int
|
||||
get_order (const char *s)
|
||||
{
|
||||
const char *names[] = { "rgba", "rgb", "bgr", "vrgb", "vbgr" };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (names); i++)
|
||||
if (strcmp (s, names[i]) == 0)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_dpi_from_gsettings (GdkWaylandScreen *screen_wayland)
|
||||
{
|
||||
@@ -271,6 +315,25 @@ get_dpi_from_gsettings (GdkWaylandScreen *screen_wayland)
|
||||
return 96.0 * factor;
|
||||
}
|
||||
|
||||
/* When using the Settings portal, we cache the value in
|
||||
* the fallback member, and we ignore the valid field
|
||||
*/
|
||||
typedef struct _TranslationEntry TranslationEntry;
|
||||
struct _TranslationEntry {
|
||||
gboolean valid;
|
||||
const gchar *schema;
|
||||
const gchar *key;
|
||||
const gchar *setting;
|
||||
GType type;
|
||||
union {
|
||||
const char *s;
|
||||
gint i;
|
||||
gboolean b;
|
||||
} fallback;
|
||||
};
|
||||
|
||||
static TranslationEntry * find_translation_entry_by_schema (const char *schema,
|
||||
const char *key);
|
||||
static void
|
||||
update_xft_settings (GdkScreen *screen)
|
||||
{
|
||||
@@ -281,25 +344,48 @@ update_xft_settings (GdkScreen *screen)
|
||||
GsdFontRgbaOrder order;
|
||||
gboolean use_rgba = FALSE;
|
||||
GsdXftSettings xft_settings;
|
||||
double dpi;
|
||||
|
||||
settings = g_hash_table_lookup (screen_wayland->settings, "org.gnome.settings-daemon.plugins.xsettings");
|
||||
|
||||
if (settings)
|
||||
if (gdk_should_use_portal ())
|
||||
{
|
||||
antialiasing = g_settings_get_enum (settings, "antialiasing");
|
||||
hinting = g_settings_get_enum (settings, "hinting");
|
||||
order = g_settings_get_enum (settings, "rgba-order");
|
||||
TranslationEntry *entry;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "antialiasing");
|
||||
antialiasing = entry->fallback.i;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "hinting");
|
||||
hinting = entry->fallback.i;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.settings-daemon.plugins.xsettings", "rgba-order");
|
||||
order = entry->fallback.i;
|
||||
|
||||
entry = find_translation_entry_by_schema ("org.gnome.desktop.interface", "text-scaling-factor");
|
||||
dpi = 96.0 * entry->fallback.i / 65536.0 * 1024; /* Xft wants 1/1024th of an inch */
|
||||
}
|
||||
else
|
||||
{
|
||||
antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
|
||||
hinting = GSD_FONT_HINTING_MEDIUM;
|
||||
order = GSD_FONT_RGBA_ORDER_RGB;
|
||||
settings = g_hash_table_lookup (screen_wayland->settings,
|
||||
"org.gnome.settings-daemon.plugins.xsettings");
|
||||
|
||||
if (settings)
|
||||
{
|
||||
antialiasing = g_settings_get_enum (settings, "antialiasing");
|
||||
hinting = g_settings_get_enum (settings, "hinting");
|
||||
order = g_settings_get_enum (settings, "rgba-order");
|
||||
}
|
||||
else
|
||||
{
|
||||
antialiasing = GSD_FONT_ANTIALIASING_MODE_GRAYSCALE;
|
||||
hinting = GSD_FONT_HINTING_MEDIUM;
|
||||
order = GSD_FONT_RGBA_ORDER_RGB;
|
||||
}
|
||||
|
||||
dpi = get_dpi_from_gsettings (screen_wayland) * 1024;
|
||||
}
|
||||
|
||||
xft_settings.antialias = (antialiasing != GSD_FONT_ANTIALIASING_MODE_NONE);
|
||||
xft_settings.hinting = (hinting != GSD_FONT_HINTING_NONE);
|
||||
xft_settings.dpi = get_dpi_from_gsettings (screen_wayland) * 1024; /* Xft wants 1/1024ths of an inch */
|
||||
xft_settings.dpi = dpi;
|
||||
xft_settings.rgba = "rgb";
|
||||
xft_settings.hintstyle = "hintfull";
|
||||
|
||||
@@ -403,20 +489,6 @@ update_xft_settings (GdkScreen *screen)
|
||||
#define WM_SETTINGS_SCHEMA "org.gnome.desktop.wm.preferences"
|
||||
#define CLASSIC_WM_SETTINGS_SCHEMA "org.gnome.shell.extensions.classic-overrides"
|
||||
|
||||
typedef struct _TranslationEntry TranslationEntry;
|
||||
struct _TranslationEntry {
|
||||
gboolean valid;
|
||||
const gchar *schema;
|
||||
const gchar *key;
|
||||
const gchar *setting;
|
||||
GType type;
|
||||
union {
|
||||
const gchar *s;
|
||||
gint i;
|
||||
gboolean b;
|
||||
} fallback;
|
||||
};
|
||||
|
||||
static TranslationEntry translations[] = {
|
||||
{ FALSE, "org.gnome.desktop.interface", "gtk-theme", "gtk-theme-name" , G_TYPE_STRING, { .s = "Adwaita" } },
|
||||
{ FALSE, "org.gnome.desktop.interface", "icon-theme", "gtk-icon-theme-name", G_TYPE_STRING, { .s = "gnome" } },
|
||||
@@ -446,31 +518,39 @@ static TranslationEntry translations[] = {
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-double-click-titlebar", "gtk-titlebar-double-click", G_TYPE_STRING, { .s = "toggle-maximize" } },
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } },
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
|
||||
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } }
|
||||
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } },
|
||||
{ FALSE, "org.gnome.fontconfig", "serial", "gtk-fontconfig-timestamp", G_TYPE_INT, { .i = 0 } }
|
||||
|
||||
};
|
||||
|
||||
static TranslationEntry *
|
||||
find_translation_entry_by_key (GSettings *settings,
|
||||
const gchar *key)
|
||||
find_translation_entry_by_schema (const char *schema,
|
||||
const gchar *key)
|
||||
{
|
||||
guint i;
|
||||
gchar *schema;
|
||||
|
||||
g_object_get (settings, "schema", &schema, NULL);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (translations); i++)
|
||||
{
|
||||
if (g_str_equal (schema, translations[i].schema) &&
|
||||
g_str_equal (key, translations[i].key))
|
||||
{
|
||||
g_free (schema);
|
||||
return &translations[i];
|
||||
}
|
||||
return &translations[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TranslationEntry *
|
||||
find_translation_entry_by_key (GSettings *settings,
|
||||
const char *key)
|
||||
{
|
||||
char *schema;
|
||||
TranslationEntry *entry;
|
||||
|
||||
g_object_get (settings, "schema", &schema, NULL);
|
||||
entry = find_translation_entry_by_schema (schema, key);
|
||||
g_free (schema);
|
||||
|
||||
return NULL;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static TranslationEntry *
|
||||
@@ -505,6 +585,78 @@ settings_changed (GSettings *settings,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
apply_portal_setting (TranslationEntry *entry,
|
||||
GVariant *value,
|
||||
GdkScreen *screen)
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
entry->fallback.s = g_intern_string (g_variant_get_string (value, NULL));
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
entry->fallback.i = g_variant_get_int32 (value);
|
||||
break;
|
||||
case G_TYPE_BOOLEAN:
|
||||
entry->fallback.b = g_variant_get_boolean (value);
|
||||
break;
|
||||
case G_TYPE_NONE:
|
||||
if (strcmp (entry->key, "antialiasing") == 0)
|
||||
entry->fallback.i = get_antialiasing (g_variant_get_string (value, NULL));
|
||||
else if (strcmp (entry->key, "hinting") == 0)
|
||||
entry->fallback.i = get_hinting (g_variant_get_string (value, NULL));
|
||||
else if (strcmp (entry->key, "rgba-order") == 0)
|
||||
entry->fallback.i = get_order (g_variant_get_string (value, NULL));
|
||||
else if (strcmp (entry->key, "text-scaling-factor") == 0)
|
||||
entry->fallback.i = (int) (g_variant_get_double (value) * 65536.0);
|
||||
update_xft_settings (screen);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
settings_portal_changed (GDBusProxy *proxy,
|
||||
const char *sender_name,
|
||||
const char *signal_name,
|
||||
GVariant *parameters,
|
||||
GdkScreen *screen)
|
||||
{
|
||||
if (strcmp (signal_name, "SettingChanged") == 0)
|
||||
{
|
||||
const char *namespace;
|
||||
const char *name;
|
||||
GVariant *value;
|
||||
TranslationEntry *entry;
|
||||
|
||||
g_variant_get (parameters, "(&s&sv)", &namespace, &name, &value);
|
||||
|
||||
entry = find_translation_entry_by_schema (namespace, name);
|
||||
if (entry != NULL)
|
||||
{
|
||||
char *a = g_variant_print (value, FALSE);
|
||||
g_debug ("Using changed portal setting %s %s: %s", namespace, name, a);
|
||||
g_free (a);
|
||||
apply_portal_setting (entry, value, screen);
|
||||
notify_setting (screen, entry->setting);
|
||||
}
|
||||
else
|
||||
g_debug ("Ignoring portal setting %s %s", namespace, name);
|
||||
|
||||
g_variant_unref (value);
|
||||
}
|
||||
}
|
||||
|
||||
static void fontconfig_dbus_proxy_open_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
|
||||
#define PORTAL_BUS_NAME "org.freedesktop.portal.Desktop"
|
||||
#define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop"
|
||||
#define PORTAL_SETTINGS_INTERFACE "org.freedesktop.portal.Settings"
|
||||
|
||||
static void
|
||||
init_settings (GdkScreen *screen)
|
||||
{
|
||||
@@ -514,6 +666,95 @@ init_settings (GdkScreen *screen)
|
||||
GSettings *settings;
|
||||
gint i;
|
||||
|
||||
if (gdk_should_use_portal ())
|
||||
{
|
||||
GVariant *ret;
|
||||
GError *error = NULL;
|
||||
const char *schema;
|
||||
GVariant *val;
|
||||
GVariantIter *iter;
|
||||
|
||||
screen_wayland->settings_portal = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
PORTAL_BUS_NAME,
|
||||
PORTAL_OBJECT_PATH,
|
||||
PORTAL_SETTINGS_INTERFACE,
|
||||
NULL,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Settings portal not found: %s", error->message);
|
||||
g_error_free (error);
|
||||
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
ret = g_dbus_proxy_call_sync (screen_wayland->settings_portal,
|
||||
"ReadAll",
|
||||
g_variant_new ("(s)", "org.gnome.*"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
G_MAXINT,
|
||||
NULL,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Failed to read portal settings: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_clear_object (&screen_wayland->settings_portal);
|
||||
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
g_variant_get (ret, "(a{sa{sv}})", &iter);
|
||||
|
||||
while (g_variant_iter_loop (iter, "{s@a{sv}}", &schema, &val))
|
||||
{
|
||||
GVariantIter *iter2 = g_variant_iter_new (val);
|
||||
const char *key;
|
||||
GVariant *v;
|
||||
|
||||
while (g_variant_iter_loop (iter2, "{sv}", &key, &v))
|
||||
{
|
||||
TranslationEntry *entry = find_translation_entry_by_schema (schema, key);
|
||||
if (entry)
|
||||
{
|
||||
char *a = g_variant_print (v, FALSE);
|
||||
g_debug ("Using portal setting for %s %s: %s\n", schema, key, a);
|
||||
g_free (a);
|
||||
apply_portal_setting (entry, v, screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Ignoring portal setting for %s %s", schema, key);
|
||||
}
|
||||
}
|
||||
g_variant_iter_free (iter2);
|
||||
}
|
||||
g_variant_iter_free (iter);
|
||||
|
||||
g_variant_unref (ret);
|
||||
|
||||
g_signal_connect (screen_wayland->settings_portal, "g-signal",
|
||||
G_CALLBACK (settings_portal_changed), screen_wayland);
|
||||
|
||||
return;
|
||||
|
||||
fallback:
|
||||
g_debug ("Failed to use Settings portal; falling back to gsettings");
|
||||
}
|
||||
|
||||
screen_wayland->dbus_cancellable = g_cancellable_new ();
|
||||
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
GTK_SETTINGS_DBUS_NAME,
|
||||
GTK_SETTINGS_DBUS_PATH,
|
||||
GTK_SETTINGS_DBUS_NAME,
|
||||
screen_wayland->dbus_cancellable,
|
||||
fontconfig_dbus_proxy_open_cb,
|
||||
screen_wayland);
|
||||
|
||||
screen_wayland->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
|
||||
|
||||
source = g_settings_schema_source_get_default ();
|
||||
@@ -581,6 +822,44 @@ set_value_from_entry (GdkScreen *screen,
|
||||
GdkWaylandScreen *screen_wayland = GDK_WAYLAND_SCREEN (screen);
|
||||
GSettings *settings;
|
||||
|
||||
if (gdk_should_use_portal ())
|
||||
{
|
||||
switch (entry->type)
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
g_value_set_string (value, entry->fallback.s);
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
|
||||
g_value_set_uint (value, (guint)entry->fallback.i);
|
||||
else
|
||||
g_value_set_int (value, entry->fallback.i);
|
||||
break;
|
||||
case G_TYPE_BOOLEAN:
|
||||
g_value_set_boolean (value, entry->fallback.b);
|
||||
break;
|
||||
case G_TYPE_NONE:
|
||||
if (g_str_equal (entry->setting, "gtk-xft-antialias"))
|
||||
g_value_set_int (value, screen_wayland->xft_settings.antialias);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-hinting"))
|
||||
g_value_set_int (value, screen_wayland->xft_settings.hinting);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-hintstyle"))
|
||||
g_value_set_static_string (value, screen_wayland->xft_settings.hintstyle);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-rgba"))
|
||||
g_value_set_static_string (value, screen_wayland->xft_settings.rgba);
|
||||
else if (g_str_equal (entry->setting, "gtk-xft-dpi"))
|
||||
g_value_set_int (value, screen_wayland->xft_settings.dpi);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
settings = (GSettings *)g_hash_table_lookup (screen_wayland->settings, entry->schema);
|
||||
switch (entry->type)
|
||||
{
|
||||
@@ -598,9 +877,12 @@ set_value_from_entry (GdkScreen *screen,
|
||||
}
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
g_value_set_int (value, settings && entry->valid
|
||||
? g_settings_get_int (settings, entry->key)
|
||||
: entry->fallback.i);
|
||||
if (g_str_equal (entry->setting, "gtk-fontconfig-timestamp"))
|
||||
g_value_set_uint (value, screen_wayland->dbus_settings.fontconfig_timestamp);
|
||||
else
|
||||
g_value_set_int (value, settings && entry->valid
|
||||
? g_settings_get_int (settings, entry->key)
|
||||
: entry->fallback.i);
|
||||
break;
|
||||
case G_TYPE_BOOLEAN:
|
||||
g_value_set_boolean (value, settings && entry->valid
|
||||
@@ -635,6 +917,12 @@ set_decoration_layout_from_entry (GdkScreen *screen,
|
||||
GSettings *settings = NULL;
|
||||
const char *session;
|
||||
|
||||
if (gdk_should_use_portal ())
|
||||
{
|
||||
g_value_set_string (value, entry->fallback.s);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hack: until we get session-dependent defaults in GSettings,
|
||||
* swap out the usual schema for the "classic" one when
|
||||
* running in classic mode
|
||||
@@ -683,7 +971,8 @@ gdk_wayland_screen_get_setting (GdkScreen *screen,
|
||||
|
||||
g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
|
||||
|
||||
if (g_settings_schema_source_get_default () == NULL)
|
||||
if (wayland_screen->settings != NULL &&
|
||||
g_hash_table_size (wayland_screen->settings) == 0)
|
||||
return FALSE;
|
||||
|
||||
entry = find_translation_entry_by_setting (name);
|
||||
@@ -984,17 +1273,6 @@ _gdk_wayland_screen_new (GdkDisplay *display)
|
||||
screen_wayland->width,
|
||||
screen_wayland->height);
|
||||
|
||||
screen_wayland->dbus_cancellable = g_cancellable_new ();
|
||||
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
GTK_SETTINGS_DBUS_NAME,
|
||||
GTK_SETTINGS_DBUS_PATH,
|
||||
GTK_SETTINGS_DBUS_NAME,
|
||||
screen_wayland->dbus_cancellable,
|
||||
fontconfig_dbus_proxy_open_cb,
|
||||
screen_wayland);
|
||||
|
||||
init_settings (screen);
|
||||
|
||||
return screen;
|
||||
|
||||
Reference in New Issue
Block a user