config: support merging multiple config files

Add the -m|--merge-config command line option to iterate backwards over
XDG Base Dir paths and read config/theme files multiple times.

For example if both ~/.config/labwc/rc.xml and /etc/xdg/labwc/rc.xml
exist, the latter will be read first and then the former (if
--merge-config is enabled).

When $XDG_CONFIG_HOME is defined, make it replace (not augment)
$HOME/.config. Similarly, make $XDG_CONFIG_DIRS replace /etc/xdg when
defined.

XDG Base Dir Spec does not specify whether or not an application (or a
compositor!) should (a) define that only the file under the most important
base directory should be used, or (b) define rules for merging the
information from the different files.

ref: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html

In the case of labwc there is a use-case for both positions, just to be
clear, the default behaviour, described by position (a) above, does NOT
change.

This change affects the following config/theme files:
  - rc.xml
  - menu.xml
  - autostart
  - environment
  - themerc
  - themerc-override
  - Theme buttons, for example max.xbm

Instead of caching global config/theme directories, create lists of paths
(e.g.  '/home/foo/.config/labwc/rc.xml', '/etc/xdg/labwc/rc.xml', etc).
This creates more common parsing logic and just reversing the direction
of iteration and breaks early if config-merge is not wanted.

Enable better fallback for themes. For example if a particular theme does
not exist in $HOME/.local/share/themes, it will be searched for in
~/.themes/ and so on. This also applies to theme buttons which now
fallback on an individual basis.

Avoid using stat() in most situations and just go straight to fopen().

Fixes #1406
This commit is contained in:
Johan Malm 2024-01-09 22:00:45 +00:00 committed by Johan Malm
parent d0aff49c81
commit 698c7ace07
14 changed files with 330 additions and 240 deletions

View file

@ -11,6 +11,7 @@
#include <wlr/util/log.h>
#include "action.h"
#include "common/buf.h"
#include "common/dir.h"
#include "common/font.h"
#include "common/list.h"
#include "common/match.h"
@ -548,21 +549,27 @@ err:
static void
parse_xml(const char *filename, struct server *server)
{
static char buf[4096] = { 0 };
struct wl_list paths;
paths_config_create(&paths, filename);
if (!rc.config_dir) {
return;
}
snprintf(buf, sizeof(buf), "%s/%s", rc.config_dir, filename);
bool should_merge_config = rc.merge_config;
struct wl_list *(*iter)(struct wl_list *list);
iter = should_merge_config ? paths_get_prev : paths_get_next;
FILE *stream = fopen(buf, "r");
if (!stream) {
wlr_log(WLR_ERROR, "cannot read %s", buf);
return;
for (struct wl_list *elm = iter(&paths); elm != &paths; elm = iter(elm)) {
struct path *path = wl_container_of(elm, path, link);
FILE *stream = fopen(path->string, "r");
if (!stream) {
return;
}
wlr_log(WLR_INFO, "read menu file %s", path->string);
parse(server, stream);
fclose(stream);
if (!should_merge_config) {
break;
}
}
wlr_log(WLR_INFO, "read menu file %s", buf);
parse(server, stream);
fclose(stream);
paths_destroy(&paths);
}
static int