Add support for config file

Closes: https://github.com/emersion/xdg-desktop-portal-wlr/issues/60
This commit is contained in:
columbarius 2021-03-03 10:29:56 +01:00 committed by GitHub
parent e103e120e2
commit 07154bb1e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 206 additions and 30 deletions

View file

@ -6,6 +6,7 @@ packages:
- pipewire-dev
- wayland-dev
- wayland-protocols
- iniparser-dev
sources:
- https://github.com/emersion/xdg-desktop-portal-wlr
tasks:

View file

@ -6,6 +6,7 @@ packages:
- wayland
- wayland-protocols
- pipewire
- iniparser
sources:
- https://github.com/emersion/xdg-desktop-portal-wlr
tasks:

View file

@ -6,6 +6,7 @@ packages:
- pkgconf
- wayland
- wayland-protocols
- iniparser
sources:
- https://github.com/emersion/xdg-desktop-portal-wlr
tasks:

2
contrib/config.sample Normal file
View file

@ -0,0 +1,2 @@
[screencast]
output=

18
include/config.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef CONFIG_H
#define CONFIG_H
#include "logger.h"
struct config_screencast {
char *output_name;
};
struct xdpw_config {
struct config_screencast screencast_conf;
};
void print_config(enum LOGLEVEL loglevel, struct xdpw_config *config);
void finish_config(struct xdpw_config *config);
void init_config(char ** const configfile, struct xdpw_config *config);
#endif

View file

@ -3,6 +3,8 @@
#include <stdio.h>
#define DEFAULT_LOGLEVEL ERROR
enum LOGLEVEL { QUIET, ERROR, WARN, INFO, DEBUG, TRACE };
struct logger_properties {

View file

@ -57,9 +57,6 @@ struct xdpw_screencast_context {
struct zxdg_output_manager_v1* xdg_output_manager;
struct wl_shm *shm;
// cli options
const char *output_name;
// sessions
struct wl_list screencast_instances;
};

View file

@ -11,6 +11,7 @@
#endif
#include "screencast_common.h"
#include "config.h"
struct xdpw_state {
struct wl_list xdpw_sessions;
@ -21,6 +22,7 @@ struct xdpw_state {
uint32_t screencast_source_types; // bitfield of enum source_types
uint32_t screencast_cursor_modes; // bitfield of enum cursor_modes
uint32_t screencast_version;
struct xdpw_config *config;
};
struct xdpw_request {
@ -41,7 +43,7 @@ enum {
};
int xdpw_screenshot_init(struct xdpw_state *state);
int xdpw_screencast_init(struct xdpw_state *state, const char *output_name);
int xdpw_screencast_init(struct xdpw_state *state);
struct xdpw_request *xdpw_request_create(sd_bus *bus, const char *object_path);
void xdpw_request_destroy(struct xdpw_request *req);

View file

@ -16,12 +16,17 @@ add_project_arguments(cc.get_supported_arguments([
'-D_POSIX_C_SOURCE=200809L',
]), language: 'c')
prefix = get_option('prefix')
sysconfdir = get_option('sysconfdir')
add_project_arguments('-DSYSCONFDIR="@0@"'.format(join_paths(prefix, sysconfdir)), language : 'c')
inc = include_directories('include')
rt = cc.find_library('rt')
pipewire = dependency('libpipewire-0.3', version: '>= 0.3.2')
wayland_client = dependency('wayland-client')
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
iniparser = cc.find_library('iniparser', dirs: [join_paths(get_option('prefix'),get_option('libdir'))])
if get_option('sd-bus-provider') == 'auto'
assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto')
@ -55,6 +60,7 @@ executable(
files([
'src/core/main.c',
'src/core/logger.c',
'src/core/config.c',
'src/core/request.c',
'src/core/session.c',
'src/screenshot/screenshot.c',
@ -69,6 +75,7 @@ executable(
sdbus,
pipewire,
rt,
iniparser,
],
include_directories: [inc],
install: true,

118
src/core/config.c Normal file
View file

@ -0,0 +1,118 @@
#include "config.h"
#include "xdpw.h"
#include "logger.h"
#include <dictionary.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iniparser.h>
void print_config(enum LOGLEVEL loglevel, struct xdpw_config *config) {
logprint(loglevel, "config: outputname %s", config->screencast_conf.output_name);
}
// NOTE: calling finish_config won't prepare the config to be read again from config file
// with init_config since to pointers and other values won't be reset to NULL, or 0
void finish_config(struct xdpw_config *config) {
logprint(DEBUG, "config: destroying config");
// screencast
free(&config->screencast_conf.output_name);
}
static void getstring_from_conffile(dictionary *d,
const char *key, char **dest, const char *fallback) {
if (*dest != NULL) {
return;
}
const char *c = iniparser_getstring(d, key, fallback);
if (c == NULL) {
return;
}
// Allow keys without value as default
if (strcmp(c, "") != 0) {
*dest = strdup(c);
} else {
*dest = fallback ? strdup(fallback) : NULL;
}
}
static bool file_exists(const char *path) {
return path && access(path, R_OK) != -1;
}
static char *config_path(char *prefix, char *filename) {
if (!prefix || !prefix[0] || !filename || !filename[0]) {
return NULL;
}
char *config_folder = "xdg-desktop-portal-wlr";
size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename);
char *path = calloc(size, sizeof(char));
snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename);
return path;
}
static void config_parse_file(const char *configfile, struct xdpw_config *config) {
dictionary *d = NULL;
if (configfile) {
logprint(INFO, "config: using config file %s", *configfile);
d = iniparser_load(configfile);
} else {
logprint(INFO, "config: no config file found");
}
if (configfile && !d) {
logprint(ERROR, "config: unable to load config file %s", configfile);
}
// screencast
getstring_from_conffile(d, "screencast:output_name", &config->screencast_conf.output_name, NULL);
iniparser_freedict(d);
logprint(DEBUG, "config: config file parsed");
print_config(DEBUG, config);
}
static char *get_config_path(void) {
const char *home = getenv("HOME");
size_t size_fallback = 1 + strlen(home) + strlen("/.config");
char *config_home_fallback = calloc(size_fallback, sizeof(char));
snprintf(config_home_fallback, size_fallback, "%s/.config", home);
char *prefix[4];
prefix[0] = getenv("XDG_CONFIG_HOME");
prefix[1] = config_home_fallback;
prefix[2] = SYSCONFDIR "/xdg";
prefix[3] = SYSCONFDIR;
char *config[2];
config[0] = getenv("XDG_CURRENT_DESKTOP");
config[1] = "config";
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 2; j++) {
char *path = config_path(prefix[i], config[j]);
if (!path) {
continue;
}
logprint(TRACE, "config: trying config file %s", path);
if (file_exists(path)) {
return path;
}
free(path);
}
}
return NULL;
}
void init_config(char ** const configfile, struct xdpw_config *config) {
if (*configfile == NULL) {
*configfile = get_config_path();
}
config_parse_file(*configfile, config);
}

View file

@ -5,17 +5,6 @@
#include <string.h>
#include <time.h>
static int NUM_LEVELS = 6;
static const char *loglevels[] = {
"QUIET",
"ERROR",
"WARN",
"INFO",
"DEBUG",
"TRACE"
};
static struct logger_properties logprops;
void init_logger(FILE *dst, enum LOGLEVEL level) {
@ -24,16 +13,43 @@ void init_logger(FILE *dst, enum LOGLEVEL level) {
}
enum LOGLEVEL get_loglevel(const char *level) {
int i;
for (i = 0; i < NUM_LEVELS; i++) {
if (!strcmp(level, loglevels[i])) {
return (enum LOGLEVEL) i;
}
if (strcmp(level, "QUIET") == 0) {
return QUIET;
} else if (strcmp(level, "ERROR") == 0) {
return ERROR;
} else if (strcmp(level, "WARN") == 0) {
return WARN;
} else if (strcmp(level, "INFO") == 0) {
return INFO;
} else if (strcmp(level, "DEBUG") == 0) {
return DEBUG;
} else if (strcmp(level, "TRACE") == 0) {
return TRACE;
}
fprintf(stderr, "Could not understand log level %s\n", level);
abort();
}
static const char *print_loglevel(enum LOGLEVEL loglevel) {
switch (loglevel) {
case QUIET:
return "QUIET";
case ERROR:
return "ERROR";
case WARN:
return "WARN";
case INFO:
return "INFO";
case DEBUG:
return "DEBUG";
case TRACE:
return "TRACE";
}
fprintf(stderr, "Could not find log level %d\n", loglevel);
abort();
}
void logprint(enum LOGLEVEL level, char *msg, ...) {
if (!logprops.dst) {
fprintf(stderr, "Logger has been called, but was not initialized\n");
@ -56,7 +72,7 @@ void logprint(enum LOGLEVEL level, char *msg, ...) {
fprintf(logprops.dst, "%s", timestr);
fprintf(logprops.dst, " ");
fprintf(logprops.dst, "[%s]", loglevels[level]);
fprintf(logprops.dst, "[%s]", print_loglevel(level));
fprintf(logprops.dst, " - ");
va_start(args, msg);

View file

@ -24,6 +24,8 @@ static int xdpw_usage(FILE* stream, int rc) {
" QUIET, ERROR, WARN, INFO, DEBUG, TRACE\n"
" -o, --output=<name> Select output to capture.\n"
" metadata (performs no conversion).\n"
" -c, --config=<config file> Select config file.\n"
" (default is $XDG_CONFIG_HOME/xdg-desktop-portal-wlr/config)\n"
" -r, --replace Replace a running instance.\n"
" -h, --help Get help (this text).\n"
"\n";
@ -39,14 +41,16 @@ static int handle_name_lost(sd_bus_message *m, void *userdata, sd_bus_error *ret
}
int main(int argc, char *argv[]) {
const char* output_name = NULL;
enum LOGLEVEL loglevel = ERROR;
struct xdpw_config config = {0};
char *configfile = NULL;
enum LOGLEVEL loglevel = DEFAULT_LOGLEVEL;
bool replace = false;
static const char* shortopts = "l:o:rh";
static const char* shortopts = "l:o:c:rh";
static const struct option longopts[] = {
{ "loglevel", required_argument, NULL, 'l' },
{ "output", required_argument, NULL, 'o' },
{ "config", required_argument, NULL, 'c' },
{ "replace", no_argument, NULL, 'r' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
@ -62,7 +66,10 @@ int main(int argc, char *argv[]) {
loglevel = get_loglevel(optarg);
break;
case 'o':
output_name = optarg;
config.screencast_conf.output_name = strdup(optarg);
break;
case 'c':
configfile = strdup(optarg);
break;
case 'r':
replace = true;
@ -75,6 +82,7 @@ int main(int argc, char *argv[]) {
}
init_logger(stderr, loglevel);
init_config(&configfile, &config);
int ret = 0;
@ -111,12 +119,13 @@ int main(int argc, char *argv[]) {
.screencast_source_types = MONITOR,
.screencast_cursor_modes = HIDDEN | EMBEDDED,
.screencast_version = XDP_CAST_PROTO_VER,
.config = &config,
};
wl_list_init(&state.xdpw_sessions);
xdpw_screenshot_init(&state);
ret = xdpw_screencast_init(&state, output_name);
ret = xdpw_screencast_init(&state);
if (ret < 0) {
logprint(ERROR, "xdpw: failed to initialize screencast");
goto error;
@ -217,6 +226,8 @@ int main(int argc, char *argv[]) {
}
// TODO: cleanup
finish_config(&config);
free(configfile);
return EXIT_SUCCESS;

View file

@ -48,8 +48,9 @@ int setup_outputs(struct xdpw_screencast_context *ctx, struct xdpw_session *sess
}
struct xdpw_wlr_output *out;
if (ctx->output_name) {
out = xdpw_wlr_output_find_by_name(&ctx->output_list, ctx->output_name);
if (ctx->state->config->screencast_conf.output_name) {
out = xdpw_wlr_output_find_by_name(&ctx->output_list,
ctx->state->config->screencast_conf.output_name);
if (!out) {
logprint(ERROR, "wlroots: no such output");
abort();
@ -434,12 +435,11 @@ static const sd_bus_vtable screencast_vtable[] = {
SD_BUS_VTABLE_END
};
int xdpw_screencast_init(struct xdpw_state *state, const char *output_name) {
int xdpw_screencast_init(struct xdpw_state *state) {
sd_bus_slot *slot = NULL;
state->screencast = (struct xdpw_screencast_context) { 0 };
state->screencast.state = state;
state->screencast.output_name = output_name;
int err;
err = xdpw_pwr_core_connect(state);