mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-22 14:35:57 +01:00
Add support for config file
Closes: https://github.com/emersion/xdg-desktop-portal-wlr/issues/60
This commit is contained in:
parent
e103e120e2
commit
07154bb1e3
13 changed files with 206 additions and 30 deletions
|
@ -6,6 +6,7 @@ packages:
|
|||
- pipewire-dev
|
||||
- wayland-dev
|
||||
- wayland-protocols
|
||||
- iniparser-dev
|
||||
sources:
|
||||
- https://github.com/emersion/xdg-desktop-portal-wlr
|
||||
tasks:
|
||||
|
|
|
@ -6,6 +6,7 @@ packages:
|
|||
- wayland
|
||||
- wayland-protocols
|
||||
- pipewire
|
||||
- iniparser
|
||||
sources:
|
||||
- https://github.com/emersion/xdg-desktop-portal-wlr
|
||||
tasks:
|
||||
|
|
|
@ -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
2
contrib/config.sample
Normal file
|
@ -0,0 +1,2 @@
|
|||
[screencast]
|
||||
output=
|
18
include/config.h
Normal file
18
include/config.h
Normal 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
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEFAULT_LOGLEVEL ERROR
|
||||
|
||||
enum LOGLEVEL { QUIET, ERROR, WARN, INFO, DEBUG, TRACE };
|
||||
|
||||
struct logger_properties {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
118
src/core/config.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue