Skip to content

Commit

Permalink
config: support loading plugins
Browse files Browse the repository at this point in the history
Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed May 23, 2024
1 parent 05e4b48 commit ade46ba
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 9 deletions.
3 changes: 3 additions & 0 deletions man/picom.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ OPTIONS
*--write-pid-path* 'PATH'::
Write process ID to a file. it is recommended to use an absolute path.

*--plugins* 'PATH'::
Specify plugins to load. Plugins will first be searched in current working directory (unless specified in the config file, in which case this step is skipped), then in `$XDG_CONFIG_HOME/picom/plugins`, then in `$XDG_CONFIG_DIRS/picom/plugins`. If all of the above fail, the plugin name is passed directly to the dynamic loader. Can be specified multiple times to load more than one plugins.

*--shadow-color* 'STRING'::
Color of shadow, as a hex string ('#000000')

Expand Down
21 changes: 13 additions & 8 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
// Copyright (c) 2013 Richard Grenville <[email protected]>

#include <ctype.h>
#include <errno.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -20,16 +18,11 @@

#include <test.h>

#include "c2.h"
#include "common.h"
#include "compiler.h"
#include "kernel.h"
#include "log.h"
#include "region.h"
#include "string_utils.h"
#include "types.h"
#include "utils.h"
#include "win.h"

#include "config.h"

Expand Down Expand Up @@ -632,6 +625,18 @@ void *parse_window_shader_prefix_with_cwd(const char *src, const char **end, voi
return parse_window_shader_prefix(src, end, cwd);
}

bool load_plugin(const char *name, const char *include_dir) {
scoped_charp path = locate_auxiliary_file("plugins", optarg, include_dir);
void *handle = NULL;
if (!path) {
handle = dlopen(name, RTLD_LAZY);
} else {
log_debug("Plugin %s resolved to %s", name, path);
handle = dlopen(path, RTLD_LAZY);
}
return handle != NULL;
}

bool parse_config(options_t *opt, const char *config_file) {
// clang-format off
*opt = (struct options){
Expand Down
2 changes: 2 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ typedef struct options {

extern const char *const BACKEND_STRS[NUM_BKEND + 1];

bool load_plugin(const char *name, const char *include_dir);

bool must_use parse_long(const char *, long *);
bool must_use parse_int(const char *, int *);
struct conv **must_use parse_blur_kern_lst(const char *, int *count);
Expand Down
31 changes: 31 additions & 0 deletions src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,37 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) {
// Get options from the configuration file. We don't do range checking
// right now. It will be done later

// Load user specified plugins at the very beginning, because list of backends
// depends on the plugins loaded.
auto plugins = config_lookup(&cfg, "plugins");
if (plugins != NULL) {
sval = config_setting_get_string(plugins);
if (sval) {
if (!load_plugin(sval, NULL)) {
log_fatal("Failed to load plugin \"%s\".", sval);
goto out;
}
} else if (config_setting_is_array(plugins) || config_setting_is_list(plugins)) {
for (int i = 0; i < config_setting_length(plugins); i++) {
sval = config_setting_get_string_elem(plugins, i);
if (!sval) {
log_fatal("Invalid value for \"plugins\" at line "
"%d.",
config_setting_source_line(plugins));
goto out;
}
if (!load_plugin(sval, NULL)) {
log_fatal("Failed to load plugin \"%s\".", sval);
goto out;
}
}
} else {
log_fatal("Invalid value for \"plugins\" at line %d.",
config_setting_source_line(plugins));
goto out;
}
}

// --dbus
lcfg_lookup_bool(&cfg, "dbus", &opt->dbus);

Expand Down
10 changes: 9 additions & 1 deletion src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ static const struct picom_option picom_options[] = {
[314] = {"show-all-xerrors", IGNORE(no_argument)},
['b'] = {"daemon" , IGNORE(no_argument) , "Daemonize process."},
[256] = {"config" , IGNORE(required_argument), "Path to the configuration file."},
[307] = {"plugins" , IGNORE(required_argument), "Plugins to load. Can be specified multiple times, each time with a single plugin."},

// Simple flags
['c'] = {"shadow" , ENABLE(shadow_enable) , "Enabled client-side shadows on windows."},
Expand Down Expand Up @@ -691,6 +692,7 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
bool *fork, int *exit_code) {
setup_longopts();

scoped_charp current_working_dir = getcwd(NULL, 0);
int o = 0, longopt_idx = -1;

// Pre-parse the command line arguments to check for --config and invalid
Expand All @@ -706,18 +708,24 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
} else if (o == 'h') {
usage(argv[0], 0);
return true;

} else if (o == 'b') {
*fork = true;
} else if (o == 314) {
*all_xerrors = true;
} else if (o == 318) {
printf("%s\n", PICOM_VERSION);
return true;
} else if (o == 307) {
// --plugin
if (!load_plugin(optarg, current_working_dir)) {
log_error("Failed to load plugin %s", optarg);
goto err;
}
} else if (o == '?' || o == ':') {
usage(argv[0], 1);
goto err;
}
// TODO(yshui) maybe log-level should be handled here.
}

// Check for abundant positional arguments
Expand Down

0 comments on commit ade46ba

Please sign in to comment.