~emersion/public-inbox

kanshi: Add special output mode "best" v1 REJECTED

: 1
 Add special output mode "best"

 4 files changed, 57 insertions(+), 11 deletions(-)
#880267 running .build.yml
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/public-inbox/patches/36709/mbox | git am -3
Learn more about email & git

[PATCH kanshi] Add special output mode "best" Export this patch

This mode will choose the output mode with the largest screen area and
highest refresh rate.
---
 include/config.h |  6 ++++++
 kanshi.5.scd     |  6 +++++-
 main.c           | 50 ++++++++++++++++++++++++++++++++++++++----------
 parser.c         |  6 ++++++
 4 files changed, 57 insertions(+), 11 deletions(-)

diff --git a/include/config.h b/include/config.h
index 8e80bf0..4a55ddc 100644
--- a/include/config.h
+++ b/include/config.h
@@ -12,6 +12,11 @@ enum kanshi_output_field {
	KANSHI_OUTPUT_TRANSFORM = 1 << 4,
};

enum kanshi_output_mode_type {
	KANSHI_OUTPUT_MODE_SPECIFIC = 1 << 0,
	KANSHI_OUTPUT_MODE_BEST = 1 << 1,
};

struct kanshi_profile_output {
	char *name;
	unsigned int fields; // enum kanshi_output_field
@@ -19,6 +24,7 @@ struct kanshi_profile_output {

	bool enabled;
	struct {
		enum kanshi_output_mode_type type;
		int width, height;
		int refresh; // mHz
	} mode;
diff --git a/kanshi.5.scd b/kanshi.5.scd
index 966af93..916c098 100644
--- a/kanshi.5.scd
+++ b/kanshi.5.scd
@@ -93,16 +93,20 @@ quoted (with *"*) if they contain spaces.
*enable*|*disable*
	Enables or disables the specified output.

*mode* <width>x<height>[@<rate>[Hz]]
*mode* <width>x<height>[@<rate>[Hz]]|best
	Configures the specified output to use the specified mode. Modes are a
	combination of width and height (in pixels) and a refresh rate (in Hz) that
	your display can be configured to use.

	"best" will use the mode with the largest screen area and highest refresh rate
	available.

	Examples:

```
		output HDMI-A-1 mode 1920x1080
		output HDMI-A-1 mode 1920x1080@60Hz
		output HDMI-A-1 mode best
```

*position* <x>,<y>
diff --git a/main.c b/main.c
index 92a520f..fc3127d 100644
--- a/main.c
+++ b/main.c
@@ -251,6 +251,24 @@ static struct kanshi_mode *match_mode(struct kanshi_head *head,
	return last_match;
}

static struct kanshi_mode *mode_best(struct kanshi_head *head) {
	struct kanshi_mode *mode;
	struct kanshi_mode *best = NULL;
	int max_area = 0;
	int max_refresh = 0;

	wl_list_for_each(mode, &head->modes, link) {
		int area = mode->width * mode->height;
		if (area > max_area || (area == max_area && mode->refresh > max_refresh)) {
			max_area = area;
			max_refresh = mode->refresh;
			best = mode;
		}
	}

	return best;
}

static void apply_profile(struct kanshi_state *state,
		struct kanshi_profile *profile,
		struct kanshi_profile_output **matches) {
@@ -294,16 +312,28 @@ static void apply_profile(struct kanshi_state *state,
			zwlr_output_configuration_v1_enable_head(config, head->wlr_head);
		if (profile_output->fields & KANSHI_OUTPUT_MODE) {
			// TODO: support custom modes
			struct kanshi_mode *mode = match_mode(head,
				profile_output->mode.width, profile_output->mode.height,
				profile_output->mode.refresh);
			if (mode == NULL) {
				fprintf(stderr,
					"output '%s' doesn't support mode '%dx%d@%fHz'\n",
					head->name,
					profile_output->mode.width, profile_output->mode.height,
					(float)profile_output->mode.refresh / 1000);
				goto error;
			struct kanshi_mode *mode = NULL;
			switch (profile_output->mode.type) {
				case KANSHI_OUTPUT_MODE_BEST:
					mode = mode_best(head);
					if (mode == NULL) {
						fprintf(stderr, "output '%s' doesn't have any modes\n", head->name);
						goto error;
					}
					break;
				case KANSHI_OUTPUT_MODE_SPECIFIC:
				default:
					mode = match_mode(head,
						profile_output->mode.width, profile_output->mode.height,
						profile_output->mode.refresh);
					if (mode == NULL) {
						fprintf(stderr,
							"output '%s' doesn't support mode '%dx%d@%fHz'\n",
							head->name,
							profile_output->mode.width, profile_output->mode.height,
							(float)profile_output->mode.refresh / 1000);
						goto error;
					}
			}
			zwlr_output_configuration_head_v1_set_mode(config_head,
				mode->wlr_mode);
diff --git a/parser.c b/parser.c
index 5b774d9..77ffb7e 100644
--- a/parser.c
+++ b/parser.c
@@ -204,6 +204,12 @@ static bool parse_mode(struct kanshi_profile_output *output, char *str) {
	const char *height = strtok(NULL, "@");
	const char *refresh = strtok(NULL, "");

	if (strcmp(width, "best") == 0) {
		output->mode.type = KANSHI_OUTPUT_MODE_BEST;
		return true;
	}
	output->mode.type = KANSHI_OUTPUT_MODE_SPECIFIC;

	if (width == NULL || height == NULL) {
		fprintf(stderr, "invalid output mode: missing width/height\n");
		return false;
-- 
2.38.1