Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for config file #75

Merged
merged 8 commits into from
Mar 3, 2021
Merged

Conversation

columbarius
Copy link
Collaborator

@columbarius columbarius commented Dec 30, 2020

Resolves #60

Note: while this is not merged and man pages are not ready, the locations for a config file are in order:

  • $XDG_CONFIG_HOME/xdg-desktop-portal-wlr/$XDG_CURRENT_DESKTOP
  • $XDG_CONFIG_HOME/xdg-desktop-portal-wlr/config
  • $HOME/.config/xdg-desktop-portal-wlr/$XDG_CURRENT_DESKTOP
  • $HOME/.config/xdg-desktop-portal-wlr/config
  • /etc/xdg/xdg-desktop-portal-wlr/$XDG_CURRENT_DESKTOP
  • /etc/xdg/xdg-desktop-portal-wlr/config
  • /etc/xdg-desktop-portal-wlr/$XDG_CURRENT_DESKTOP
  • /etc/xdg-desktop-portal-wlr/config

The system wide config can be in another place, if SYSCONFDIR differs from /etc

@danshick
Copy link
Collaborator

Nice. What should the syntax be for a command to determine the output instead of a fixed output string? If the config had both, which would take precedence?

I don't think it is important to implement arbitrary output command handling now, but i think we should have a plan for the syntax and behavior.

@columbarius
Copy link
Collaborator Author

Nice. What should the syntax be for a command to determine the output instead of a fixed output string? If the config had both, which would take precedence?

I think that depends, if we want to have a set of hardcoded default choosers or not. If we have one, we need a way to hard override the chooser with a given monitor. If you could disable all choosers (like adding an empty chooser entry) it would be irrelevant, if you first skip the choosers and then take the set monitor or choose the set monitor in the first place. So i would let the hardcoded output be priority.

I don't think it is important to implement arbitrary output command handling now, but i think we should have a plan for the syntax and behavior.

For an arbitrary output chooser, we would just need two options in the file. chooser_cmd and chooser_type. Those would override the hardcoded ones. Question is, if we want to fail screencast, if no monitor is selected, or if we still pick the "first" one?

I could rebase #59 onto this MR.

@danshick
Copy link
Collaborator

danshick commented Dec 31, 2020

I could rebase #59 onto this MR.

I was thinking of landing this one first, then going back to #59 and just adding the needed config entries.

My initial thoughts for config would be

chooser_type = <first | fixed | command>

chooser_cmd = <string representation of command to run, should accept list of outputs on stdin and output the choice on stdout, ignored for all types but command>

chooser_value = <string representation of output string, ignores for all types other than fixed>

I wonder if we should define an ini section for these settings. I think it makes sense to fall back to first if nothing is specified or a chooser fails.

@columbarius
Copy link
Collaborator Author

I added my thought on how to config the chooser in #59.
We could adapt it in a way that type=none would use output_name or chooser_value to select a monitor directly.

@columbarius
Copy link
Collaborator Author

I would also look at /etc/xdg/xdg-desktop-portal-wlr/{DESKTOP,config} before /etc/xdg-desktop-portal-wlr/... for a config to be compliant with xdg spec.
@danshick @emersion is there still something to work on, or can I squash and clean everything up for review?

@danshick
Copy link
Collaborator

danshick commented Jan 4, 2021

I would also look at /etc/xdg/xdg-desktop-portal-wlr/{DESKTOP,config} before /etc/xdg-desktop-portal-wlr/... for a config to be compliant with xdg spec.

Makes sense.

@danshick @emersion is there still something to work on, or can I squash and clean everything up for review?

Nope, looks good to me.

include/config.h Outdated

#include "logger.h"

struct config_general {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need that many structs? Can't we just have a single struct with two fields?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's more like a personal preference, to have one struct for each portal to create some kind of namespace separation. Currently all options could be in one struct.

@columbarius
Copy link
Collaborator Author

@emersion
I think I addressed all open points except the nested structs of the config struct. I like it more that way, but if you want, I can flatten them. Ready for a new review, if you have time.

include/config.h Outdated
};

struct config_logger {
enum LOGLEVEL loglevel;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, is there a use-case for setting the log level in the config file? The logging level mostly exists for debugging purposes, which means manually starting xdpw.

For instance, Sway doesn't have an option to set it from the config file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to put every option we have into one central config structure. If we want, we can read it from the configfile, of not, we wont.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's worthwhile if that's just adding code for no real purpose.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of like this because starting xdpw manually can be a pain. This would change verbosity in journald if it is started via dbus activation as a systemd user service.

This would mean people running master could keep log verbosity up all the time without overriding the service file.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the use-case here.

You almost never want DEBUG/TRACE levels when running with D-Bus activation, because that'd fill up your hard drive. When running on master, you likely don't have the version you compiled installed, otherwise it would conflict with the one from your package manager. Even if you want DEBUG/TRACE and you have master installed to /usr, then you'd need to edit your config file, restart xdpw (how?), reproduce the bug, then use journalctl to watch/collect the logs, then revert the config file change.

It sounds a lot easier to just run xdpw from the build directory, with the log level flag, redirecting the output to a file.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emersion I think the problem is that when we ask people in issues to give us logs, they often get confused by the process of killing all instances of xdp/xdpw and starting both from the command line in such a way that the right instances are picked up and used. They're not often building from source. I've seen people suggesting overriding the systemd units just to get logs. If you're developing xdpw, running from the command line is a must, but for regular users, this is confusing.

I think your recent patch to add the -r flag will help a lot with this and may invalidate my concerns. Maybe, in addition to this, improved documentation would help in the FAQ or README.

Even when I'm testing a PR, I typically hack a PKGBUILD together that points to another fork so that I can rely on d-bus activation for a few days to test out the stability of the changes. It is nice to have logging up a little (not TRACE level, but DEBUG isn't too bad). This helps for more pervasive issues that are harder to catch other than by regular use.

The more I write this out, the more I think wanting a config file option for this is the exception and not the rule. Overriding the systemd unit may not be such a bad thing to have to do in the exceptional case.

Copy link
Collaborator Author

@columbarius columbarius Feb 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding the -r flag will make this issue invalid, since the default loglevel is error, so the log will hopefully contain the reason of failure and for a more detailed log the installed version of xdpw can be used with --reload -l DEBUG/TRACE.
The only usecase left would be people which want reduce the loglevel to QUIET.
But i would guess, that that's not a very useful or often used choice.

include/config.h Outdated
#include "logger.h"

struct config_general {
char *configfile;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need this in the config file struct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same idea, it's one option, which will only be set by commandline parameter (or maybe environment variable). This should (can) not be read from the configfile, but it also serves as a placeholder for general settings, which might/will come later.
Also it's nice for debugging, if you can dump the state/all settings of xdpw.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have this as a separate variable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok also regarding the loglevel: the config should only contain configs for each portal?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would remove the loglevel from config and the configfile setting with it's corresponding structs, so only the output_name for the screecast struct would stay

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that sounds good to me. We'll add more config options as we go.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Side note, it's always easier to add new config options, than to remove existing ones. Removing config options means we break user configurations.)

@oranenj
Copy link

oranenj commented Feb 19, 2021

As a user testing this out, my primary gripe with this PR is that it needs documentation. I had to run xdpw with tracelogging on to figure out what files it actually tries to load. :/ A short manual page would be ideal.

Also, could reasonable defaults be hardcoded into the system? Like, if there's something to choose, use slurp automatically unless configured otherwise, and if it fails, default to picking the first display? I generally prefer software to do something sane without having to configure it.

@columbarius
Copy link
Collaborator Author

columbarius commented Feb 19, 2021

@oranenj Added a note about the locations at the description of this PR. Documentation will either follow in the wiki or with #67 as soon as this is merged. Thanks for pointing that out. I didn't realize, that those MR's are widely used.

I'm also preferring sane defaults and if you don't have a config file the output chooser should try 3 different choosers (I admit, we could differentiate if the screencast was declined, or if the chooser was not installed), but please feel free to suggest your idea at #59.

@danshick
Copy link
Collaborator

@oranenj

Re: documentation, man pages are planned. I've been working on them for what feels like a decade, but I keep getting side tracked. They'll come out soon and we will update them with this PR if they land first, and they will include this PR if they land second. Also, this PR will likely get merged with the output selection PR, so both will need to be ready before either is stabilized. In the future, updating docs should be a criteria for accepted PRs, but I doubt docs will ever get written before something is ready to be merged.

I like sane defaults as well, but I'm not a big fan of hardcoding the names of other programs into a codebase. We've already got a hard dependency on grim (for screenshots), so slurp doesn't feel like a big stretch. I'm very wary of adding any others, but I might be in the minority on this one. I think we will always gracefully fall back to the first display and have a CLI flag that takes precedence over any chooser, just in case.

@oranenj
Copy link

oranenj commented Feb 19, 2021

@danshick I totally agree with you on dependencies. In this case though, slurp wouldn't be as much a dependency as an extremely convenient integration, and since it's sort of part of the "wlroots ecosystem" it feels justified. If you don't feel like hardcoding it in C, one option might be to ship a "default configuration" in /usr/share somewhere that's not meant to be edited (and will be overwritten by package managers) which will be used as a last resort.

@danshick
Copy link
Collaborator

danshick commented Feb 19, 2021

one option might be to ship a "default configuration" in /usr/share somewhere that's not meant to be edited (and will be overwritten by package managers) which will be used as a last resort.

I like this idea a lot. Also lets different distros ship a custom default config if they so choose.

What does everyone else think? @emersion @columbarius?

@columbarius
Copy link
Collaborator Author

Depends... if we make slurp (with the specific commit) a hard dependency, we could ship a default config in /user/share with an slurp entry. If not, we would ship an almost empty config file such that xdpw falls back to the default path. That way, I would not ship a config, but try to create the most sane default possible and rely on the distribution to ship something in etc reflecting their choice.

@oranenj
Copy link

oranenj commented Feb 20, 2021

I might be a good idea to nudge distributions towards using the defaults from upstream. Otherwise, you might end up having to support users using very different configurations just because distros happen to pick whatever they think is best at the moment of packaging if upstream has no opinion on the matter.

@columbarius
Copy link
Collaborator Author

columbarius commented Feb 20, 2021

Since we are writing stuff for a library which could be used to write window managers and desktop environments i don't think there is something like a good upstream default, since we can assume very little as preinstalled. With a config file, we can only support one output chooser, while currently we have three assumptions as default, if the config has no configured chooser.
Afaics we have the options:

  • Ship a upstream config with probably slurp configured and have slurp as a dependency. If slurp fails, or is not installed xdpw will deny all screencast since the chooser failed. If a specific wm/de wants to ship it's own chooser, it can ship a config file, which will override ours.
  • Ship no upstream config file or an empty one and try a list of hardcoded somehow reasonable choosers (eg. slurp, wofi, bemenu, (dmenu in case of wayland support)). If nothing is installed take the first monitor. But this fallback is only reasonable in this single case. If a wm/de chooses otherwise, the same custom config as above should be true.


void init_config(char *configfile, struct xdpw_config *config) {
if (configfile == NULL) {
configfile = get_config_path();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This memory is never free'd. This wouldn't be the biggest memory leak in xdpw, that said.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this memory be freed here at the end of main?
Well better not make that a contest ^^'

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment only changes the local configfile variable. The variable in main is unaffected.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

damn, yeah screwed that up. Should work now.


void init_config(char *configfile, struct xdpw_config *config) {
if (configfile == NULL) {
configfile = get_config_path();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should check configfile != NULL at this point. get_config_path can return NULL.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but afaics libiniparser could handle NULL as a path to the config file and will insert the defaults as if this file is empty. If you want to avoid this, I could write another function setting the default values manually.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Owner

@emersion emersion Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(IMHO just set the defaults in main when initializing the config variable)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens here https://github.com/ndevilla/iniparser/blob/f858275f7f307eecba84c2f5429483f9f28007f8/src/iniparser.c#L419

About defaulting in main is, i can't detect if something is a default or was set via commandline parameter.

Copy link
Owner

@emersion emersion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks almost good for merging. I think this will be my last review round.

}

static void config_parse_file(const char *configfile, struct xdpw_config *config) {
dictionary *d = iniparser_load(configfile);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check for a NULL d here, in case iniparser_load failed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, if d is NULL iniparser_get* will just return the fallback.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but if iniparser failed to read the file we want a proper error message

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added logging, but don't know how to supress the log from iniparser. We could check before and skip it when the config file is null, or just have the line in the log.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, which log from iniparser?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is the line
iniparser: cannot open (NIL) or path to file
in stderr if iniparser_load fails.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe don't call iniparser_load if configfile == NULL?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved all checks of configfile to the part where we load it with iniparser_load, so we don't have to check for the same things multiple times.

src/core/main.c Outdated
@@ -217,6 +226,8 @@ int main(int argc, char *argv[]) {
}

// TODO: cleanup
finish_config(&config);
free((char *)configfile);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something that we need to free can't be const

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope i got the const and not const declaration right this time.

Copy link
Owner

@emersion emersion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@emersion emersion merged commit 07154bb into emersion:master Mar 3, 2021
@columbarius
Copy link
Collaborator Author

Thanks for the squash and merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Config file format
6 participants