mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
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:
parent
d0aff49c81
commit
698c7ace07
14 changed files with 330 additions and 240 deletions
|
|
@ -18,6 +18,19 @@ searched for in the following order:
|
|||
- ${XDG_CONFIG_HOME:-$HOME/.config}/labwc
|
||||
- ${XDG_CONFIG_DIRS:-/etc/xdg}/labwc
|
||||
|
||||
When $XDG_CONFIG_HOME is defined, it replaces (rather than augments)
|
||||
$HOME/.config. The same is the case for $XDG_CONFIG_DIRS and /etc/xdg.
|
||||
|
||||
The XDG Base Directory Specification does not specify whether or not programs
|
||||
should (a) allow the first-identified configuration file to supersede any
|
||||
others, or (b) define rules for merging the information from more than one file.
|
||||
|
||||
By default, labwc uses option (a), reading only the first file identified. With
|
||||
the --merge-config option, the search order is reserved, but every configuration
|
||||
file encountered is processed in turn. Thus, user-specific files will augment
|
||||
system-wide configurations, with conflicts favoring the user-specific
|
||||
alternative.
|
||||
|
||||
The configuration directory location can be override with the -C command line
|
||||
option.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ searched for in the following order:
|
|||
- /usr/local/share/themes/<theme-name>/openbox-3/
|
||||
- /opt/share/themes/<theme-name>/openbox-3/
|
||||
|
||||
When $XDG_DATA_HOME is defined, it replaces (rather than augments)
|
||||
$HOME/.local/share. The same is the case for $XDG_DATA_DIRS and /usr/share/.
|
||||
|
||||
Choosing a theme is done by editing the <name> key in the <theme> section of
|
||||
the rc.xml configuration file (labwc-config(5)).
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ the `--exit` and `--reconfigure` options use.
|
|||
*-h, --help*
|
||||
Show help message and quit
|
||||
|
||||
*-m, --merge-config*
|
||||
Merge user config/theme files in all XDG Base Directories
|
||||
|
||||
*-r, --reconfigure*
|
||||
Reload the compositor configuration
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,19 @@
|
|||
#ifndef LABWC_DIR_H
|
||||
#define LABWC_DIR_H
|
||||
|
||||
char *config_dir(void);
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
/**
|
||||
* theme_dir - find theme directory containing theme @theme_name
|
||||
* @theme_name: theme to search for
|
||||
*/
|
||||
char *theme_dir(const char *theme_name);
|
||||
struct path {
|
||||
char *string;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wl_list *paths_get_prev(struct wl_list *elm);
|
||||
struct wl_list *paths_get_next(struct wl_list *elm);
|
||||
|
||||
void paths_config_create(struct wl_list *paths, const char *filename);
|
||||
void paths_theme_create(struct wl_list *paths, const char *theme_name,
|
||||
const char *filename);
|
||||
void paths_destroy(struct wl_list *paths);
|
||||
|
||||
#endif /* LABWC_DIR_H */
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ struct window_switcher_field {
|
|||
|
||||
struct rcxml {
|
||||
char *config_dir;
|
||||
bool merge_config;
|
||||
|
||||
/* core */
|
||||
bool xdg_shell_server_side_deco;
|
||||
|
|
|
|||
|
|
@ -4,17 +4,15 @@
|
|||
|
||||
/**
|
||||
* session_environment_init - set enrivonment variables based on <key>=<value>
|
||||
* @dir: path to config directory
|
||||
* pairs in `${XDG_CONFIG_DIRS:-/etc/xdg}/lawbc/environment` with user override
|
||||
* in `${XDG_CONFIG_HOME:-$HOME/.config}`
|
||||
*/
|
||||
void session_environment_init(const char *dir);
|
||||
void session_environment_init(void);
|
||||
|
||||
/**
|
||||
* session_autostart_init - run autostart file as shell script
|
||||
* @dir: path to config directory
|
||||
* Note: Same as `sh ~/.config/labwc/autostart` (or equivalent XDG config dir)
|
||||
*/
|
||||
void session_autostart_init(const char *dir);
|
||||
void session_autostart_init(void);
|
||||
|
||||
#endif /* LABWC_SESSION_H */
|
||||
|
|
|
|||
|
|
@ -1,11 +1,27 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "button/common.h"
|
||||
#include "common/dir.h"
|
||||
#include "config/rcxml.h"
|
||||
#include "labwc.h"
|
||||
|
||||
void
|
||||
button_filename(const char *name, char *buf, size_t len)
|
||||
{
|
||||
snprintf(buf, len, "%s/%s", theme_dir(rc.theme_name), name);
|
||||
struct wl_list paths;
|
||||
paths_theme_create(&paths, rc.theme_name, name);
|
||||
|
||||
/*
|
||||
* You can't really merge buttons, so let's just iterate forwards
|
||||
* and stop on the first hit
|
||||
*/
|
||||
struct path *path;
|
||||
wl_list_for_each(path, &paths, link) {
|
||||
if (access(path->string, R_OK) == 0) {
|
||||
snprintf(buf, len, "%s", path->string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
paths_destroy(&paths);
|
||||
}
|
||||
|
|
|
|||
193
src/common/dir.c
193
src/common/dir.c
|
|
@ -4,143 +4,190 @@
|
|||
*
|
||||
* Copyright Johan Malm 2020
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <glib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include "common/dir.h"
|
||||
#include "common/buf.h"
|
||||
#include "common/list.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/string-helpers.h"
|
||||
#include "labwc.h"
|
||||
|
||||
struct dir {
|
||||
const char *prefix;
|
||||
const char *default_prefix;
|
||||
const char *path;
|
||||
};
|
||||
|
||||
static struct dir config_dirs[] = {
|
||||
{ "XDG_CONFIG_HOME", "labwc" },
|
||||
{ "HOME", ".config/labwc" },
|
||||
{ "XDG_CONFIG_DIRS", "labwc" },
|
||||
{ NULL, "/etc/xdg/labwc" },
|
||||
{ NULL, NULL }
|
||||
{
|
||||
.prefix = "XDG_CONFIG_HOME",
|
||||
.default_prefix = "$HOME/.config",
|
||||
.path = "labwc"
|
||||
}, {
|
||||
.prefix = "XDG_CONFIG_DIRS",
|
||||
.default_prefix = "/etc/xdg",
|
||||
.path = "labwc",
|
||||
}, {
|
||||
.path = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
static struct dir theme_dirs[] = {
|
||||
{ "XDG_DATA_HOME", "themes" },
|
||||
{ "HOME", ".local/share/themes" },
|
||||
{ "HOME", ".themes" },
|
||||
{ "XDG_DATA_DIRS", "themes" },
|
||||
{ NULL, "/usr/share/themes" },
|
||||
{ NULL, "/usr/local/share/themes" },
|
||||
{ NULL, "/opt/share/themes" },
|
||||
{ NULL, NULL }
|
||||
{
|
||||
.prefix = "XDG_DATA_HOME",
|
||||
.default_prefix = "$HOME/.local/share",
|
||||
.path = "themes",
|
||||
}, {
|
||||
.prefix = "HOME",
|
||||
.path = ".themes",
|
||||
}, {
|
||||
.prefix = "XDG_DATA_DIRS",
|
||||
.default_prefix = "/usr/share:/usr/local/share:/opt/share",
|
||||
.path = "themes",
|
||||
}, {
|
||||
.path = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
static bool
|
||||
isdir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
return (!stat(path, &st) && S_ISDIR(st.st_mode));
|
||||
}
|
||||
|
||||
struct ctx {
|
||||
void (*build_path_fn)(struct ctx *ctx, char *prefix, const char *path);
|
||||
const char *filename;
|
||||
char *buf;
|
||||
size_t len;
|
||||
struct dir *dirs;
|
||||
const char *theme_name;
|
||||
struct wl_list *list;
|
||||
};
|
||||
|
||||
struct wl_list *paths_get_prev(struct wl_list *elm) { return elm->prev; }
|
||||
struct wl_list *paths_get_next(struct wl_list *elm) { return elm->next; }
|
||||
|
||||
static void
|
||||
build_config_path(struct ctx *ctx, char *prefix, const char *path)
|
||||
{
|
||||
if (!prefix) {
|
||||
snprintf(ctx->buf, ctx->len, "%s", path);
|
||||
} else {
|
||||
snprintf(ctx->buf, ctx->len, "%s/%s", prefix, path);
|
||||
}
|
||||
assert(prefix);
|
||||
snprintf(ctx->buf, ctx->len, "%s/%s/%s", prefix, path, ctx->filename);
|
||||
}
|
||||
|
||||
static void
|
||||
build_theme_path(struct ctx *ctx, char *prefix, const char *path)
|
||||
{
|
||||
if (!prefix) {
|
||||
snprintf(ctx->buf, ctx->len, "%s/%s/openbox-3", path,
|
||||
ctx->theme_name);
|
||||
} else {
|
||||
snprintf(ctx->buf, ctx->len, "%s/%s/%s/openbox-3", prefix, path,
|
||||
ctx->theme_name);
|
||||
}
|
||||
assert(prefix);
|
||||
snprintf(ctx->buf, ctx->len, "%s/%s/%s/openbox-3/%s", prefix, path,
|
||||
ctx->theme_name, ctx->filename);
|
||||
}
|
||||
|
||||
static char *
|
||||
static void
|
||||
find_dir(struct ctx *ctx)
|
||||
{
|
||||
char *debug = getenv("LABWC_DEBUG_DIR_CONFIG_AND_THEME");
|
||||
|
||||
for (int i = 0; ctx->dirs[i].path; i++) {
|
||||
struct dir d = ctx->dirs[i];
|
||||
if (!d.prefix) {
|
||||
/* handle /etc/xdg... */
|
||||
ctx->build_path_fn(ctx, NULL, d.path);
|
||||
struct buf prefix;
|
||||
buf_init(&prefix);
|
||||
|
||||
/*
|
||||
* Replace (rather than augment) $HOME/.config with
|
||||
* $XDG_CONFIG_HOME if defined, and so on for the other
|
||||
* XDG Base Directories.
|
||||
*/
|
||||
char *pfxenv = getenv(d.prefix);
|
||||
buf_add(&prefix, pfxenv ? pfxenv : d.default_prefix);
|
||||
if (!prefix.len) {
|
||||
free(prefix.buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle .default_prefix shell variables such as $HOME */
|
||||
buf_expand_shell_variables(&prefix);
|
||||
|
||||
/*
|
||||
* Respect that $XDG_DATA_DIRS can contain multiple colon
|
||||
* separated paths and that we have structured the
|
||||
* .default_prefix in the same way.
|
||||
*/
|
||||
gchar * *prefixes;
|
||||
prefixes = g_strsplit(prefix.buf, ":", -1);
|
||||
for (gchar * *p = prefixes; *p; p++) {
|
||||
ctx->build_path_fn(ctx, *p, d.path);
|
||||
if (debug) {
|
||||
fprintf(stderr, "%s\n", ctx->buf);
|
||||
}
|
||||
if (isdir(ctx->buf)) {
|
||||
return ctx->buf;
|
||||
}
|
||||
} else {
|
||||
/* handle $HOME/.config/... and $XDG_* */
|
||||
char *prefix = getenv(d.prefix);
|
||||
if (!prefix) {
|
||||
continue;
|
||||
}
|
||||
gchar * *prefixes;
|
||||
prefixes = g_strsplit(prefix, ":", -1);
|
||||
for (gchar * *p = prefixes; *p; p++) {
|
||||
ctx->build_path_fn(ctx, *p, d.path);
|
||||
if (debug) {
|
||||
fprintf(stderr, "%s\n", ctx->buf);
|
||||
}
|
||||
if (isdir(ctx->buf)) {
|
||||
g_strfreev(prefixes);
|
||||
return ctx->buf;
|
||||
}
|
||||
}
|
||||
g_strfreev(prefixes);
|
||||
|
||||
/*
|
||||
* TODO: We could stat() and continue here if we really
|
||||
* wanted to only respect only the first hit, but feels
|
||||
* like it is probably overkill.
|
||||
*/
|
||||
struct path *path = znew(*path);
|
||||
path->string = xstrdup(ctx->buf);
|
||||
wl_list_append(ctx->list, &path->link);
|
||||
}
|
||||
g_strfreev(prefixes);
|
||||
free(prefix.buf);
|
||||
}
|
||||
/* no directory was found */
|
||||
ctx->buf[0] = '\0';
|
||||
return ctx->buf;
|
||||
}
|
||||
|
||||
char *
|
||||
config_dir(void)
|
||||
void
|
||||
paths_config_create(struct wl_list *paths, const char *filename)
|
||||
{
|
||||
static char buf[4096] = { 0 };
|
||||
if (buf[0] != '\0') {
|
||||
return buf;
|
||||
char buf[4096] = { 0 };
|
||||
wl_list_init(paths);
|
||||
|
||||
/*
|
||||
* If user provided a config directory with the -C command line option,
|
||||
* then that trumps everything else and we do not create the
|
||||
* XDG-Base-Dir list.
|
||||
*/
|
||||
if (rc.config_dir) {
|
||||
struct path *path = znew(*path);
|
||||
path->string = strdup_printf("%s/%s", rc.config_dir, filename);
|
||||
wl_list_append(paths, &path->link);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ctx ctx = {
|
||||
.build_path_fn = build_config_path,
|
||||
.filename = filename,
|
||||
.buf = buf,
|
||||
.len = sizeof(buf),
|
||||
.dirs = config_dirs
|
||||
.dirs = config_dirs,
|
||||
.list = paths,
|
||||
};
|
||||
return find_dir(&ctx);
|
||||
find_dir(&ctx);
|
||||
}
|
||||
|
||||
char *
|
||||
theme_dir(const char *theme_name)
|
||||
void
|
||||
paths_theme_create(struct wl_list *paths, const char *theme_name,
|
||||
const char *filename)
|
||||
{
|
||||
static char buf[4096] = { 0 };
|
||||
wl_list_init(paths);
|
||||
struct ctx ctx = {
|
||||
.build_path_fn = build_theme_path,
|
||||
.filename = filename,
|
||||
.buf = buf,
|
||||
.len = sizeof(buf),
|
||||
.dirs = theme_dirs,
|
||||
.theme_name = theme_name
|
||||
.theme_name = theme_name,
|
||||
.list = paths,
|
||||
};
|
||||
return find_dir(&ctx);
|
||||
find_dir(&ctx);
|
||||
}
|
||||
|
||||
void
|
||||
paths_destroy(struct wl_list *paths)
|
||||
{
|
||||
struct path *path, *next;
|
||||
wl_list_for_each_safe(path, next, paths, link) {
|
||||
free(path->string);
|
||||
wl_list_remove(&path->link);
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "action.h"
|
||||
#include "common/dir.h"
|
||||
#include "common/list.h"
|
||||
#include "common/macros.h"
|
||||
#include "common/mem.h"
|
||||
|
|
@ -1473,69 +1474,68 @@ validate(void)
|
|||
validate_actions();
|
||||
}
|
||||
|
||||
static void
|
||||
rcxml_path(char *buf, size_t len)
|
||||
{
|
||||
if (!rc.config_dir) {
|
||||
return;
|
||||
}
|
||||
snprintf(buf, len, "%s/rc.xml", rc.config_dir);
|
||||
}
|
||||
|
||||
static void
|
||||
find_config_file(char *buffer, size_t len, const char *filename)
|
||||
{
|
||||
if (filename) {
|
||||
snprintf(buffer, len, "%s", filename);
|
||||
return;
|
||||
}
|
||||
rcxml_path(buffer, len);
|
||||
}
|
||||
|
||||
void
|
||||
rcxml_read(const char *filename)
|
||||
{
|
||||
FILE *stream;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
struct buf b;
|
||||
static char rcxml[4096] = {0};
|
||||
|
||||
rcxml_init();
|
||||
|
||||
/*
|
||||
* rcxml_read() can be called multiple times, but we only set rcxml[]
|
||||
* the first time. The specified 'filename' is only respected the first
|
||||
* time.
|
||||
*/
|
||||
if (rcxml[0] == '\0') {
|
||||
find_config_file(rcxml, sizeof(rcxml), filename);
|
||||
}
|
||||
if (rcxml[0] == '\0') {
|
||||
wlr_log(WLR_INFO, "cannot find rc.xml config file");
|
||||
goto no_config;
|
||||
struct wl_list paths;
|
||||
|
||||
if (filename) {
|
||||
/* Honour command line argument -c <filename> */
|
||||
wl_list_init(&paths);
|
||||
struct path *path = znew(*path);
|
||||
path->string = xstrdup(filename);
|
||||
wl_list_append(&paths, &path->link);
|
||||
} else {
|
||||
paths_config_create(&paths, "rc.xml");
|
||||
}
|
||||
|
||||
/* Reading file into buffer before parsing - better for unit tests */
|
||||
stream = fopen(rcxml, "r");
|
||||
if (!stream) {
|
||||
wlr_log(WLR_ERROR, "cannot read (%s)", rcxml);
|
||||
goto no_config;
|
||||
}
|
||||
wlr_log(WLR_INFO, "read config file %s", rcxml);
|
||||
buf_init(&b);
|
||||
while (getline(&line, &len, stream) != -1) {
|
||||
char *p = strrchr(line, '\n');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
struct buf b;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* This is the equivalent of a wl_list_for_each() which optionally
|
||||
* iterates in reverse depending on 'should_merge_config'
|
||||
*
|
||||
* If not merging, we iterate forwards and break after the first
|
||||
* iteration.
|
||||
*
|
||||
* If merging, we iterate backwards (least important XDG Base Dir first)
|
||||
* and keep going.
|
||||
*/
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
buf_add(&b, line);
|
||||
}
|
||||
free(line);
|
||||
fclose(stream);
|
||||
rcxml_parse_xml(&b);
|
||||
free(b.buf);
|
||||
no_config:
|
||||
|
||||
wlr_log(WLR_INFO, "read config file %s", path->string);
|
||||
|
||||
buf_init(&b);
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
while (getline(&line, &len, stream) != -1) {
|
||||
char *p = strrchr(line, '\n');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
}
|
||||
buf_add(&b, line);
|
||||
}
|
||||
zfree(line);
|
||||
fclose(stream);
|
||||
rcxml_parse_xml(&b);
|
||||
zfree(b.buf);
|
||||
if (!should_merge_config) {
|
||||
break;
|
||||
}
|
||||
};
|
||||
paths_destroy(&paths);
|
||||
post_processing();
|
||||
validate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
#include <sys/stat.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "common/buf.h"
|
||||
#include "common/dir.h"
|
||||
#include "common/file-helpers.h"
|
||||
#include "common/spawn.h"
|
||||
#include "common/string-helpers.h"
|
||||
#include "config/session.h"
|
||||
#include "labwc.h"
|
||||
|
||||
static bool
|
||||
string_empty(const char *s)
|
||||
|
|
@ -45,14 +47,15 @@ error:
|
|||
free(value.buf);
|
||||
}
|
||||
|
||||
static void
|
||||
/* return true on successful read */
|
||||
static bool
|
||||
read_environment_file(const char *filename)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
FILE *stream = fopen(filename, "r");
|
||||
if (!stream) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
wlr_log(WLR_INFO, "read environment file %s", filename);
|
||||
while (getline(&line, &len, stream) != -1) {
|
||||
|
|
@ -64,15 +67,7 @@ read_environment_file(const char *filename)
|
|||
}
|
||||
free(line);
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
static char *
|
||||
build_path(const char *dir, const char *filename)
|
||||
{
|
||||
if (string_empty(dir) || string_empty(filename)) {
|
||||
return NULL;
|
||||
}
|
||||
return strdup_printf("%s/%s", dir, filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -96,7 +91,7 @@ update_activation_env(const char *env_keys)
|
|||
}
|
||||
|
||||
void
|
||||
session_environment_init(const char *dir)
|
||||
session_environment_init(void)
|
||||
{
|
||||
/*
|
||||
* Set default for XDG_CURRENT_DESKTOP so xdg-desktop-portal-wlr is happy.
|
||||
|
|
@ -114,32 +109,49 @@ session_environment_init(const char *dir)
|
|||
*/
|
||||
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 0);
|
||||
|
||||
char *environment = build_path(dir, "environment");
|
||||
if (!environment) {
|
||||
return;
|
||||
struct wl_list paths;
|
||||
paths_config_create(&paths, "environment");
|
||||
|
||||
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;
|
||||
|
||||
for (struct wl_list *elm = iter(&paths); elm != &paths; elm = iter(elm)) {
|
||||
struct path *path = wl_container_of(elm, path, link);
|
||||
bool success = read_environment_file(path->string);
|
||||
if (success && !should_merge_config) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_environment_file(environment);
|
||||
free(environment);
|
||||
paths_destroy(&paths);
|
||||
}
|
||||
|
||||
void
|
||||
session_autostart_init(const char *dir)
|
||||
session_autostart_init(void)
|
||||
{
|
||||
/* Update dbus and systemd user environment, each may fail gracefully */
|
||||
update_activation_env("DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP");
|
||||
|
||||
char *autostart = build_path(dir, "autostart");
|
||||
if (!autostart) {
|
||||
return;
|
||||
struct wl_list paths;
|
||||
paths_config_create(&paths, "autostart");
|
||||
|
||||
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;
|
||||
|
||||
for (struct wl_list *elm = iter(&paths); elm != &paths; elm = iter(elm)) {
|
||||
struct path *path = wl_container_of(elm, path, link);
|
||||
if (!file_exists(path->string)) {
|
||||
continue;
|
||||
}
|
||||
wlr_log(WLR_INFO, "run autostart file %s", path->string);
|
||||
char *cmd = strdup_printf("sh %s", path->string);
|
||||
spawn_async_no_shell(cmd);
|
||||
free(cmd);
|
||||
|
||||
if (!should_merge_config) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file_exists(autostart)) {
|
||||
wlr_log(WLR_ERROR, "no autostart file");
|
||||
goto out;
|
||||
}
|
||||
wlr_log(WLR_INFO, "run autostart file %s", autostart);
|
||||
char *cmd = strdup_printf("sh %s", autostart);
|
||||
spawn_async_no_shell(cmd);
|
||||
free(cmd);
|
||||
out:
|
||||
free(autostart);
|
||||
paths_destroy(&paths);
|
||||
}
|
||||
|
|
|
|||
17
src/main.c
17
src/main.c
|
|
@ -21,6 +21,7 @@ static const struct option long_options[] = {
|
|||
{"debug", no_argument, NULL, 'd'},
|
||||
{"exit", no_argument, NULL, 'e'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"merge-config", no_argument, NULL, 'm'},
|
||||
{"reconfigure", no_argument, NULL, 'r'},
|
||||
{"startup", required_argument, NULL, 's'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
|
|
@ -35,6 +36,7 @@ static const char labwc_usage[] =
|
|||
" -d, --debug Enable full logging, including debug information\n"
|
||||
" -e, --exit Exit the compositor\n"
|
||||
" -h, --help Show help message and quit\n"
|
||||
" -m, --merge-config Merge user config files/theme in all XDG Base Dirs\n"
|
||||
" -r, --reconfigure Reload the compositor configuration\n"
|
||||
" -s, --startup <command> Run command on startup\n"
|
||||
" -v, --version Show version number and quit\n"
|
||||
|
|
@ -91,7 +93,7 @@ main(int argc, char *argv[])
|
|||
int c;
|
||||
while (1) {
|
||||
int index = 0;
|
||||
c = getopt_long(argc, argv, "c:C:dehrs:vV", long_options, &index);
|
||||
c = getopt_long(argc, argv, "c:C:dehmrs:vV", long_options, &index);
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -100,7 +102,7 @@ main(int argc, char *argv[])
|
|||
config_file = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
rc.config_dir = xstrdup(optarg);
|
||||
rc.config_dir = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
verbosity = WLR_DEBUG;
|
||||
|
|
@ -108,6 +110,9 @@ main(int argc, char *argv[])
|
|||
case 'e':
|
||||
send_signal_to_labwc_pid(SIGTERM);
|
||||
exit(0);
|
||||
case 'm':
|
||||
rc.merge_config = true;
|
||||
break;
|
||||
case 'r':
|
||||
send_signal_to_labwc_pid(SIGHUP);
|
||||
exit(0);
|
||||
|
|
@ -133,11 +138,7 @@ main(int argc, char *argv[])
|
|||
|
||||
die_on_detecting_suid();
|
||||
|
||||
if (!rc.config_dir) {
|
||||
rc.config_dir = config_dir();
|
||||
}
|
||||
wlr_log(WLR_INFO, "using config dir (%s)\n", rc.config_dir);
|
||||
session_environment_init(rc.config_dir);
|
||||
session_environment_init();
|
||||
rcxml_read(config_file);
|
||||
|
||||
/*
|
||||
|
|
@ -171,7 +172,7 @@ main(int argc, char *argv[])
|
|||
|
||||
menu_init(&server);
|
||||
|
||||
session_autostart_init(rc.config_dir);
|
||||
session_autostart_init();
|
||||
if (startup_cmd) {
|
||||
spawn_async_no_shell(startup_cmd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ reload_config_and_theme(void)
|
|||
static int
|
||||
handle_sighup(int signal, void *data)
|
||||
{
|
||||
session_environment_init(rc.config_dir);
|
||||
session_environment_init();
|
||||
reload_config_and_theme();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
82
src/theme.c
82
src/theme.c
|
|
@ -23,6 +23,7 @@
|
|||
#include "common/font.h"
|
||||
#include "common/graphic-helpers.h"
|
||||
#include "common/match.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/string-helpers.h"
|
||||
#include "config/rcxml.h"
|
||||
#include "button/button-png.h"
|
||||
|
|
@ -664,60 +665,36 @@ process_line(struct theme *theme, char *line)
|
|||
}
|
||||
|
||||
static void
|
||||
theme_read(struct theme *theme, const char *theme_name)
|
||||
theme_read(struct theme *theme, struct wl_list *paths)
|
||||
{
|
||||
FILE *stream = NULL;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
char themerc[4096];
|
||||
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;
|
||||
|
||||
if (strlen(theme_dir(theme_name))) {
|
||||
snprintf(themerc, sizeof(themerc), "%s/themerc",
|
||||
theme_dir(theme_name));
|
||||
stream = fopen(themerc, "r");
|
||||
}
|
||||
if (!stream) {
|
||||
if (theme_name) {
|
||||
wlr_log(WLR_INFO, "cannot find theme %s", theme_name);
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
wlr_log(WLR_INFO, "read theme %s", themerc);
|
||||
while (getline(&line, &len, stream) != -1) {
|
||||
char *p = strrchr(line, '\n');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
|
||||
wlr_log(WLR_INFO, "read theme %s", path->string);
|
||||
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
while (getline(&line, &len, stream) != -1) {
|
||||
char *p = strrchr(line, '\n');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
}
|
||||
process_line(theme, line);
|
||||
}
|
||||
process_line(theme, line);
|
||||
}
|
||||
free(line);
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
static void
|
||||
theme_read_override(struct theme *theme)
|
||||
{
|
||||
char f[4096] = { 0 };
|
||||
snprintf(f, sizeof(f), "%s/themerc-override", rc.config_dir);
|
||||
|
||||
FILE *stream = fopen(f, "r");
|
||||
if (!stream) {
|
||||
wlr_log(WLR_INFO, "no theme override '%s'", f);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO, "read theme-override %s", f);
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
while (getline(&line, &len, stream) != -1) {
|
||||
char *p = strrchr(line, '\n');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
zfree(line);
|
||||
fclose(stream);
|
||||
if (!should_merge_config) {
|
||||
break;
|
||||
}
|
||||
process_line(theme, line);
|
||||
}
|
||||
free(line);
|
||||
fclose(stream);
|
||||
}
|
||||
|
||||
struct rounded_corner_ctx {
|
||||
|
|
@ -1001,10 +978,15 @@ theme_init(struct theme *theme, const char *theme_name)
|
|||
theme_builtin(theme);
|
||||
|
||||
/* Read <data-dir>/share/themes/$theme_name/openbox-3/themerc */
|
||||
theme_read(theme, theme_name);
|
||||
struct wl_list paths;
|
||||
paths_theme_create(&paths, theme_name, "themerc");
|
||||
theme_read(theme, &paths);
|
||||
paths_destroy(&paths);
|
||||
|
||||
/* Read <config-dir>/labwc/themerc-override */
|
||||
theme_read_override(theme);
|
||||
paths_config_create(&paths, "themerc-override");
|
||||
theme_read(theme, &paths);
|
||||
paths_destroy(&paths);
|
||||
|
||||
post_processing(theme);
|
||||
create_corners(theme);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue