Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use all requested setting backends again [cont] #1538

Merged
merged 11 commits into from
Dec 21, 2024
Merged
94 changes: 75 additions & 19 deletions src/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,41 +58,97 @@ G_DEFINE_TYPE_WITH_CODE (Settings, settings, XDP_DBUS_TYPE_SETTINGS_SKELETON,

G_DEFINE_AUTOPTR_CLEANUP_FUNC (Settings, g_object_unref)

static void
merge_impl_settings (GHashTable *merged,
GVariant *settings)
{
GVariantIter iter;
const char *namespace;
GVariant *nsvalue;

g_variant_iter_init (&iter, settings);
while (g_variant_iter_next (&iter, "{&s@a{sv}}", &namespace, &nsvalue))
{
g_autoptr (GVariant) owned_nsvalue = NULL;
g_autofree char *owned_namespace = NULL;
g_autoptr (GVariantDict) dict = NULL;
GVariantIter iter2;
const char *key;
GVariant *value;

owned_nsvalue = nsvalue;

if (!g_hash_table_steal_extended (merged, namespace,
(gpointer *)&owned_namespace,
(gpointer *)&dict))
{
dict = g_variant_dict_new (NULL);
owned_namespace = g_strdup (namespace);
}

g_variant_iter_init (&iter2, nsvalue);
while (g_variant_iter_loop (&iter2, "{sv}", &key, &value))
g_variant_dict_insert_value (dict, key, value);

g_hash_table_insert (merged,
g_steal_pointer (&owned_namespace),
g_steal_pointer (&dict));
}
}

static GVariant *
merged_to_variant (GHashTable *merged)
{
g_auto(GVariantBuilder) builder =
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a{sa{sv}})"));
const char *namespace;
GVariantDict *dict;
GHashTableIter iter;

g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));

g_hash_table_iter_init (&iter, merged);
while (g_hash_table_iter_next (&iter,
(gpointer *)&namespace,
(gpointer *)&dict))
{
g_variant_builder_add (&builder, "{s@a{sv}}",
namespace,
g_variant_dict_end (dict));
}

g_variant_builder_close (&builder);

return g_variant_ref_sink (g_variant_builder_end (&builder));
}

static gboolean
settings_handle_read_all (XdpDbusSettings *object,
GDBusMethodInvocation *invocation,
const char * const *arg_namespaces)
{
g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("(a{sa{sv}})"));
g_autoptr(GHashTable) merged = NULL;
g_autoptr(GVariant) settings = NULL;
int j;

g_variant_builder_open (builder, G_VARIANT_TYPE ("a{sa{sv}}"));
merged = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) g_variant_dict_unref);

for (j = 0; j < n_impls; j++)
for (j = n_impls - 1; j >= 0; j--)
{
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) impl_value = NULL;

if (!xdp_dbus_impl_settings_call_read_all_sync (impls[j], arg_namespaces,
&impl_value, NULL, &error))
{
g_warning ("Failed to ReadAll() from Settings implementation: %s", error->message);
}
g_warning ("Failed to ReadAll() from Settings implementation: %s", error->message);
else
{
size_t i;

for (i = 0; i < g_variant_n_children (impl_value); ++i)
{
g_autoptr(GVariant) child = g_variant_get_child_value (impl_value, i);
g_variant_builder_add_value (builder, child);
}
}
merge_impl_settings (merged, impl_value);
}

g_variant_builder_close (builder);

g_dbus_method_invocation_return_value (invocation, g_variant_builder_end (builder));
settings = merged_to_variant (merged);
g_dbus_method_invocation_return_value (invocation, settings);

return G_DBUS_METHOD_INVOCATION_HANDLED;
}
Expand All @@ -107,7 +163,7 @@ settings_handle_read (XdpDbusSettings *object,

g_debug ("Read %s %s", arg_namespace, arg_key);

for (i = 0; i < n_impls; i++)
for (i = 0; i < n_impls; i++)
{
g_autoptr(GError) error = NULL;
g_autoptr(GVariant) impl_value = NULL;
Expand Down
3 changes: 2 additions & 1 deletion src/xdg-desktop-portal.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ static GOptionEntry entries[] = {
{ NULL }
};

XdpDbusImplLockdown *lockdown;

static void
message_handler (const gchar *log_domain,
GLogLevelFlags log_level,
Expand Down Expand Up @@ -208,7 +210,6 @@ on_bus_acquired (GDBusConnection *connection,
XdpPortalImplementation *implementation;
XdpPortalImplementation *lockdown_impl;
XdpPortalImplementation *access_impl;
XdpDbusImplLockdown *lockdown = NULL;
GQuark portal_errors G_GNUC_UNUSED;
GPtrArray *impls;
g_autoptr(GError) error = NULL;
Expand Down
179 changes: 114 additions & 65 deletions src/xdp-portal-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,16 @@ load_portal_configuration_for_dir (gboolean opt_verbose,
}

if (strcmp (ifaces[i], "default") == 0)
default_portal = g_steal_pointer (&interface);
{
if (default_portal == NULL)
default_portal = g_steal_pointer (&interface);
else
g_warning ("Duplicate default key will get ignored");
}
else
g_ptr_array_add (interfaces, g_steal_pointer (&interface));
{
g_ptr_array_add (interfaces, g_steal_pointer (&interface));
}
}

portal_config->n_ifaces = interfaces->len;
Expand Down Expand Up @@ -622,6 +629,56 @@ find_portal_implementation_iface (const PortalInterface *iface)
return NULL;
}

static void
_add_all_portal_implementations_iface (const PortalInterface *iface,
const char *interface,
GPtrArray *impls)
{
g_autofree char *portals = NULL;

portals = g_strjoinv (";", iface->portals);
g_debug ("Found '%s' in configuration for %s", portals, iface->dbus_name);

for (size_t i = 0; iface->portals && iface->portals[i]; i++)
{
const char *portal = iface->portals[i];

for (const GList *l = implementations; l != NULL; l = l->next)
{
XdpPortalImplementation *impl = l->data;

if (!g_str_equal (impl->source, portal) && !g_str_equal (portal, "*"))
swick marked this conversation as resolved.
Show resolved Hide resolved
continue;

if (g_ptr_array_find (impls, impl, NULL))
{
g_info ("Duplicate backend %s.portal. Skipping...", impl->source);
continue;
}

if (!portal_impl_supports_iface (impl, interface))
{
g_info ("Requested backend %s.portal does not support %s. Skipping...",
impl->source, interface);
continue;
}

g_debug ("Using %s.portal for %s (config)", impl->source, interface);
g_ptr_array_add (impls, impl);
}
}
}

static void
add_all_portal_implementations_iface (const PortalInterface *iface,
GPtrArray *impls)
{
if (iface == NULL)
return;

_add_all_portal_implementations_iface (iface, iface->dbus_name, impls);
}

static XdpPortalImplementation *
find_default_implementation_iface (const char *interface)
{
Expand All @@ -631,6 +688,7 @@ find_default_implementation_iface (const char *interface)
return NULL;

iface = config->default_portal;

for (size_t i = 0; iface->portals && iface->portals[i]; i++)
{
XdpPortalImplementation *impl;
Expand All @@ -649,6 +707,44 @@ find_default_implementation_iface (const char *interface)
return NULL;
}

static void
add_all_default_portal_implementations_iface (const char *interface,
GPtrArray *impls)
{
if (config == NULL || config->default_portal == NULL)
return;

_add_all_portal_implementations_iface (config->default_portal, interface, impls);
}

static XdpPortalImplementation *
find_gtk_fallback_portal_implementation (const char *interface)
{
/* As a last resort, if nothing was selected for this desktop by
* ${desktop}-portals.conf or portals.conf, and no portal volunteered
* itself as suitable for this desktop via the legacy UseIn mechanism,
* try to fall back to x-d-p-gtk, which has historically been the portal
* UI backend used by desktop environments with no backend of their own.
* If it isn't installed, that is not an error: we just don't use it. */
for (GList *l = implementations; l != NULL; l = l->next)
{
XdpPortalImplementation *impl = l->data;

if (!g_str_equal (impl->dbus_name, "org.freedesktop.impl.portal.desktop.gtk"))
continue;

if (!portal_impl_supports_iface (impl, interface))
continue;

g_warning ("Choosing %s.portal for %s as a last-resort fallback",
impl->source, interface);

return impl;
}

return NULL;
}

XdpPortalImplementation *
find_portal_implementation (const char *interface)
{
Expand Down Expand Up @@ -695,59 +791,30 @@ find_portal_implementation (const char *interface)
}
}

/* As a last resort, if nothing was selected for this desktop by
* ${desktop}-portals.conf or portals.conf, and no portal volunteered
* itself as suitable for this desktop via the legacy UseIn mechanism,
* try to fall back to x-d-p-gtk, which has historically been the portal
* UI backend used by desktop environments with no backend of their own.
* If it isn't installed, that is not an error: we just don't use it. */
for (GList *l = implementations; l != NULL; l = l->next)
{
XdpPortalImplementation *impl = l->data;

if (!g_str_equal (impl->dbus_name, "org.freedesktop.impl.portal.desktop.gtk"))
continue;

if (!portal_impl_supports_iface (impl, interface))
continue;

g_warning ("Choosing %s.portal for %s as a last-resort fallback",
impl->source, interface);
warn_please_use_portals_conf ();
return impl;
}

return NULL;
return find_gtk_fallback_portal_implementation (interface);
}

GPtrArray *
find_all_portal_implementations (const char *interface)
{
const char **desktops;
GPtrArray *impls;
PortalInterface *iface;
XdpPortalImplementation *gtk_fallback;
g_autoptr(GPtrArray) impls = NULL;

impls = g_ptr_array_new ();

if (portal_interface_prefers_none (interface))
return impls;

if (config)
{
PortalInterface *iface = find_matching_iface_config (interface);
XdpPortalImplementation *impl = find_portal_implementation_iface (iface);
return g_steal_pointer (&impls);

if (!impl)
impl = find_default_implementation_iface(interface);

if (impl != NULL)
{
g_debug ("Using %s.portal for %s (config)", impl->source, interface);
g_ptr_array_add (impls, impl);
}
}
iface = find_matching_iface_config (interface);
add_all_portal_implementations_iface (iface, impls);
if (impls->len > 0)
return g_steal_pointer (&impls);

add_all_default_portal_implementations_iface (interface, impls);
if (impls->len > 0)
return impls;
return g_steal_pointer (&impls);

desktops = get_current_lowercase_desktops ();

Expand All @@ -773,29 +840,11 @@ find_all_portal_implementations (const char *interface)
}

if (impls->len > 0)
return impls;

/* As a last resort, if nothing was selected for this desktop by
* ${desktop}-portals.conf or portals.conf, and no portal volunteered
* itself as suitable for this desktop via the legacy UseIn mechanism,
* try to fall back to x-d-p-gtk, which has historically been the portal
* UI backend used by desktop environments with no backend of their own.
* If it isn't installed, that is not an error: we just don't use it. */
for (GList *l = implementations; l != NULL; l = l->next)
{
XdpPortalImplementation *impl = l->data;

if (!g_str_equal (impl->dbus_name, "org.freedesktop.impl.portal.desktop.gtk"))
continue;

if (!portal_impl_supports_iface (impl, interface))
continue;
return g_steal_pointer (&impls);

g_warning ("Choosing %s.portal for %s as a last-resort fallback",
impl->source, interface);
warn_please_use_portals_conf ();
g_ptr_array_add (impls, impl);
}
gtk_fallback = find_gtk_fallback_portal_implementation (interface);
if (gtk_fallback)
g_ptr_array_add (impls, gtk_fallback);

return impls;
return g_steal_pointer (&impls);
}
Loading
Loading