Skip to content

Commit

Permalink
portal-impl: fix config ordering
Browse files Browse the repository at this point in the history
Quoting portals.conf(5):

> Each key in the group contains a semi-colon separated list of portal backend
> implementation, to be searched for an implementation of the requested interface,
> in the same order as specified in the configuration file.

But this wasn't actually true.  If the portals were set to z;y and z
and y both implemented the same portal, y would be used.

Fixing this requires reworking how portals are selected — going
through the config file and selecting the first available configured
portal, rather than going through each known portal and checking
whether it's allowed in the config file.

find_all_portal_implementations() is unchanged.  The portal-first
approach is fine for it, and it would be difficult for it to share as
much code with find_portal_implementation() now that it's written to
stop as soon as a configured portal is found.

Fixes: flatpak#1111
  • Loading branch information
alyssais authored and SoumyaRanjanPatnaik committed Jun 15, 2024
1 parent 7209054 commit 43b89c1
Showing 1 changed file with 93 additions and 28 deletions.
121 changes: 93 additions & 28 deletions src/portal-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,77 @@ warn_please_use_portals_conf (void)
"configuration file");
}

static PortalImplementation *
find_fallback_portal_implementation (const char *interface)
{
/* x-d-p-gtk 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 (const GList *l = implementations; l != NULL; l = l->next)
{
PortalImplementation *impl = l->data;

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

if (!g_strv_contains ((const char **)impl->interfaces, 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;
}

static PortalImplementation *
find_any_portal_implementation (const char *interface)
{
for (const GList *l = implementations; l != NULL; l = l->next)
{
PortalImplementation *impl = l->data;

if (!g_strv_contains ((const char **)impl->interfaces, interface))
continue;

g_debug ("Falling back to %s.portal for %s", impl->source, interface);
return impl;
}

return find_fallback_portal_implementation (interface);
}

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

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

if (g_str_equal (portal, "none"))
return NULL;

if (g_str_equal (portal, "*"))
return find_any_portal_implementation (iface->dbus_name);

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

if (g_str_equal (portal, impl->source))
return impl;
}

g_debug ("%s.portal is unrecognized", portal);
}

return find_any_portal_implementation (iface->dbus_name);
}

PortalImplementation *
find_portal_implementation (const char *interface)
{
Expand All @@ -604,14 +675,30 @@ find_portal_implementation (const char *interface)
if (portal_interface_prefers_none (interface))
return NULL;

for (l = implementations; l != NULL; l = l->next)
if (config)
{
PortalImplementation *impl = l->data;
PortalImplementation *impl = NULL;
gboolean overridden = FALSE;

if (!g_strv_contains ((const char **)impl->interfaces, interface))
continue;
/* Interfaces have precedence over the "default" catch all,
* to allow for specific interfaces to override the default
*/
for (i = 0; i < config->n_ifaces; i++)
{
const PortalInterface *iface = config->interfaces[i];

if (portal_impl_matches_config (impl, interface))
if (g_str_equal (iface->dbus_name, interface))
{
overridden = TRUE;
impl = find_portal_implementation_iface (iface);
break;
}
}

if (!overridden && !impl)
impl = find_portal_implementation_iface (config->default_portal);

if (impl != NULL)
{
g_debug ("Using %s.portal for %s (config)", impl->source, interface);
return impl;
Expand Down Expand Up @@ -641,29 +728,7 @@ 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 (l = implementations; l != NULL; l = l->next)
{
PortalImplementation *impl = l->data;

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

if (!g_strv_contains ((const char **)impl->interfaces, 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_fallback_portal_implementation (interface);
}

GPtrArray *
Expand Down

0 comments on commit 43b89c1

Please sign in to comment.