Skip to content

Commit

Permalink
Make the search order for portals.conf consistent with mimeapps.list
Browse files Browse the repository at this point in the history
Previously, we would search for a user-specific portals.conf as
highest precedence, and then iterate through desktop environments,
searching for a user-specific desktop-specific file followed by a
system-wide desktop-specific file. Now, the precedence order is
consistently that directories are most important, we only pay
attention to desktop environments within a single directory, and
desktop-specific configuration is always higher-precedence than generic
within the same directory.

Previously, desktop environments and OS vendors had to install their
per-desktop configuration into /etc, contradicting the general design
principle of putting defaults in /usr and reserving /etc for sysadmin
overrides. Now, we search both /etc and /usr/share (with typical
environment variables and build-time settings).

Previously, we didn't fully follow the XDG Base Directory specification
when looking up per-user configuration; now we do. This is potentially
significant for users who have more than one per-user directory, for
example a machine-specific directory within a home directory shared
between machines.

Update documentation accordingly.

Resolves: #1081
Signed-off-by: Simon McVittie <smcv@collabora.com>
  • Loading branch information
smcv authored and GeorgesStavracas committed Aug 24, 2023
1 parent e838ed0 commit e7027b7
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 47 deletions.
86 changes: 74 additions & 12 deletions doc/portals-conf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,57 @@ DESCRIPTION

xdg-desktop-portal uses a configuration file to determine which portal backend
should be used to provide the implementation for the requested interface.

The configuration file can be found in the following locations:

- ``/etc/xdg-desktop-portal/portals.conf``, for site-wide configuration

- ``$XDG_CONFIG_HOME/xdg-desktop-portal/portals.conf``, for user-specific
configuration

Additionally, every desktop environment can provide a portal configuration file
named ``DESKTOP-portals.conf``, where ``DESKTOP`` is the lowercase name also
used in the ``XDG_CURRENT_DESKTOP`` environment variable.
This mechanism is very similar to the freedesktop.org specification for
"Association between MIME types and applications" (mime-apps).

Desktop environments and OS vendors should provide a default configuration
for their chosen portal backends in
``/usr/share/xdg-desktop-portal/DESKTOP-portals.conf``, where ``DESKTOP``
is the desktop environment name as it would appear in the
``XDG_CURRENT_DESKTOP`` environment variable, after case-folding ASCII
upper case to lower case.
For example, KDE should provide ``/usr/share/xdg-desktop-portal/kde-portals.conf``.

Users can override those defaults, or provide configuration for an otherwise
unsupported desktop environment, by writing a file
``~/.config/xdg-desktop-portal/portals.conf``. Users of more than one
desktop environment can use desktop-specific filenames such as
``kde-portals.conf`` which will only be used in the appropriate desktop
environment.

Similarly, system administrators can provide a default configuration for
all users in ``/etc/xdg-desktop-portal/DESKTOP-portals.conf`` or
``/etc/xdg-desktop-portal/portals.conf``.

The following locations are searched for configuration, highest precedence
first:

- ``$XDG_CONFIG_HOME``, defaulting to ``~/.config``
- each directory in ``$XDG_CONFIG_DIRS``, defaulting to ``/etc/xdg``
- the build-time ``sysconfdir`` for xdg-desktop-portal, usually ``/etc``
- ``$XDG_DATA_HOME``, defaulting to ``~/.local/share``
(searched only for consistency with other specifications, writing
configuration here is not recommended)
- each directory in ``$XDG_DATA_DIRS``, defaulting to ``/usr/local/share:/usr/share``
- the build-time ``datadir`` for xdg-desktop-portal, usually ``/usr/share``

In each of those locations, for each desktop environment name listed in the
``XDG_CURRENT_DESKTOP`` environment variable, xdg-desktop-portal checks for
``xdg-desktop-portal/DESKTOP-portals.conf``, where ``DESKTOP`` is the
desktop environment name in lower-case. If a desktop-environment-specific
configuration file is not found, a non-desktop-specific file
``xdg-desktop-portal/portals.conf`` will be read.
For example, if ``XDG_CURRENT_DESKTOP`` is set to ``Budgie:GNOME``,
then xdg-desktop-portal will look for
``xdg-desktop-portal/budgie-portals.conf``,
``xdg-desktop-portal/gnome-portals.conf`` and
``xdg-desktop-portal/portals.conf`` in that order.

Only the first configuration file found is read, and lower-precedence
configuration files are ignored. All possible configuration files within
one directory are tried before moving on to the next directory, so for
example ``~/.config/xdg-desktop-portal/portals.conf`` is higher-precedence
than ``/usr/share/xdg-desktop-portal/kde-portals.conf``.

FILE FORMAT
-----------
Expand Down Expand Up @@ -75,13 +115,35 @@ EXAMPLE
ENVIRONMENT
-----------

``XDG_CURRENT_DESKTOP``

A colon-separated list of desktop environments, most specific first,
used to choose a desktop-specific portal configuration.
The default is an empty list.

``XDG_CONFIG_HOME``

The per-user ``portals.conf`` file is located in this directory. The default
is ``$HOME/.config``
is ``$HOME/.config``.

``XDG_CONFIG_DIRS``

A colon-separated list of system configuration directories and secondary
per-user configuration directories. The default is ``/etc/xdg``.

``XDG_DATA_HOME``

A per-user data directory, searched for consistency with other
specifications. The default is ``$HOME/.local/share``.

``XDG_DATA_DIRS``

A colon-separated list of system data directories and secondary per-user
data directories. The default is ``/usr/local/share:/usr/share``.

SEE ALSO
--------

- `XDG Base Directory Specification <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_
- `XDG Desktop Entry specification <https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html>`_
- `XDG Association between MIME type and applications specification <https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html>`_
123 changes: 88 additions & 35 deletions src/portal-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,61 +387,114 @@ load_portal_configuration_for_dir (gboolean opt_verbose,
return NULL;
}

/*
* Returns: %TRUE if configuration was found in @dir
*/
static gboolean
load_config_directory (const char *dir,
const char **desktops,
gboolean opt_verbose)
{
g_autoptr(PortalConfig) conf = NULL;

for (size_t i = 0; desktops[i] != NULL; i++)
{
g_autofree char *portals_conf = g_strdup_printf ("%s-portals.conf", desktops[i]);

conf = load_portal_configuration_for_dir (opt_verbose, dir, portals_conf);

if (conf != NULL)
{
if (opt_verbose)
g_debug ("Using portal configuration file '%s/%s' for desktop '%s'",
dir, portals_conf, desktops[i]);

config = g_steal_pointer (&conf);
return TRUE;
}
}

conf = load_portal_configuration_for_dir (opt_verbose, dir, "portals.conf");

if (conf != NULL)
{
if (opt_verbose)
g_debug ("Using portal configuration file '%s/%s' for non-specific desktop",
dir, "portals.conf");

config = g_steal_pointer (&conf);
return TRUE;
}

return FALSE;
}

#define XDP_SUBDIR "xdg-desktop-portal"

void
load_portal_configuration (gboolean opt_verbose)
{
g_autoptr(PortalConfig) conf = NULL;
g_autofree char *user_portal_dir = NULL;
const char * const *dirs;
const char * const *iter;
const char **desktops;
const char *portal_dir;

desktops = get_current_lowercase_desktops ();

/* We need to override this in the tests */
portal_dir = g_getenv ("XDG_DESKTOP_PORTAL_DIR");
if (portal_dir == NULL)
portal_dir = SYSCONFDIR "/xdg-desktop-portal";

user_portal_dir = g_build_filename (g_get_user_config_dir (),
"xdg-desktop-portal",
NULL);
if (portal_dir != NULL)
{
load_config_directory (portal_dir, desktops, opt_verbose);
/* All other config directories are ignored when this is set */
return;
}

/* $XDG_CONFIG_HOME/xdg-desktop-portal/(DESKTOP-)portals.conf */
user_portal_dir = g_build_filename (g_get_user_config_dir (), XDP_SUBDIR, NULL);

conf = load_portal_configuration_for_dir (opt_verbose, user_portal_dir, "portals.conf");
if (conf != NULL)
if (load_config_directory (user_portal_dir, desktops, opt_verbose))
return;

/* $XDG_CONFIG_DIRS/xdg-desktop-portal/(DESKTOP-)portals.conf */
dirs = g_get_system_config_dirs ();

for (iter = dirs; iter != NULL && *iter != NULL; iter++)
{
if (opt_verbose)
g_debug ("Using user portal configuration file");
g_autofree char *dir = g_build_filename (*iter, XDP_SUBDIR, NULL);

config = g_steal_pointer (&conf);
if (load_config_directory (dir, desktops, opt_verbose))
return;
}

desktops = get_current_lowercase_desktops ();
for (size_t i = 0; desktops[i] != NULL; i++)
{
g_autofree char *portals_conf = g_strdup_printf ("%s-portals.conf", desktops[i]);
/* ${sysconfdir}/xdg-desktop-portal/(DESKTOP-)portals.conf */
if (load_config_directory (SYSCONFDIR "/" XDP_SUBDIR, desktops, opt_verbose))
return;

conf = load_portal_configuration_for_dir (opt_verbose, user_portal_dir, portals_conf);
if (conf != NULL)
{
if (opt_verbose)
g_debug ("Using user portal configuration file '%s' for desktop '%s'",
portals_conf,
desktops[i]);
/* $XDG_DATA_HOME/xdg-desktop-portal/(DESKTOP-)portals.conf
* (just for consistency with other XDG specifications) */
g_clear_pointer (&user_portal_dir, g_free);
user_portal_dir = g_build_filename (g_get_user_data_dir (), XDP_SUBDIR, NULL);

config = g_steal_pointer (&conf);
return;
}
if (load_config_directory (user_portal_dir, desktops, opt_verbose))
return;

conf = load_portal_configuration_for_dir (opt_verbose, portal_dir, portals_conf);
if (conf != NULL)
{
if (opt_verbose)
g_debug ("Using system portal configuration file '%s' for desktop '%s'",
portals_conf,
desktops[i]);
/* $XDG_DATA_DIRS/xdg-desktop-portal/(DESKTOP-)portals.conf */
dirs = g_get_system_data_dirs ();

config = g_steal_pointer (&conf);
return;
}
for (iter = dirs; iter != NULL && *iter != NULL; iter++)
{
g_autofree char *dir = g_build_filename (*iter, XDP_SUBDIR, NULL);

if (load_config_directory (dir, desktops, opt_verbose))
return;
}

/* ${datadir}/xdg-desktop-portal/(DESKTOP-)portals.conf */
if (load_config_directory (DATADIR "/" XDP_SUBDIR, desktops, opt_verbose))
return;
}

static gboolean
Expand Down

0 comments on commit e7027b7

Please sign in to comment.