~emersion/public-inbox

1

[PATCH kanshi v3 2/2] Improve the make-model-serial matching of outputs

Details
Message ID
<20220404144220.94312-3-ivan.oleynikov95@gmail.com>
DKIM signature
pass
Download raw message
Patch: +40 -4
Previously, the matching algorithm was looking for user-configured
output name as a substring in "$output_description ($output_name)". This
lead to unexpected behaviour when you have two outputs where the one's
description is a substring of the other's.

For example, say, you have monitors "hello (DP-1)" and "hello world
(DP-2)" and you're trying to match them in your Kanshi config using

profile {
  output "hello" …
  output "hello world" …
}

Substring matching allows "hello" to be matched with either of the
outputs, and the profile may end up being applied or rejected depending
on the order in which the outputs are discovered: if "hello world
(DP-2)" is discovered first, it gets matched with "hello", while "hello
world" fails to match with "hello (DP-1)".

This patch makes Kanshi discover the actual values of output's make,
model and serial; and then compares the user-supplied matching
string with "$make $model $serial" instead of looking for it in the
description. This is exactly how swaymsg forms the output descriptions
[1], so the user can simply copy-paste the output descriptions from
swaymsg into Kanshi config and have it uniquely identified.

To implement that, this patch takes advantage of the version 2 of
wlr-output-management-unstable-v1.xml protocol.

This patch fixes my issue [2] that I reported (I don't know if it fixes
the issues of others reported there).

[1]: https://github.com/swaywm/sway/blob/master/swaymsg/main.c#L218
[2]: https://todo.sr.ht/~emersion/kanshi/54
---
 include/kanshi.h |  1 +
 main.c           | 43 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/include/kanshi.h b/include/kanshi.h
index 22b8f47..2fc6a8a 100644
--- a/include/kanshi.h
+++ b/include/kanshi.h
@@ -25,6 +25,7 @@ struct kanshi_head {
	struct wl_list link;

	char *name, *description;
	char *make, *model, *serial_number;
	int32_t phys_width, phys_height; // mm
	struct wl_list modes;

diff --git a/main.c b/main.c
index db34789..30ab330 100644
--- a/main.c
+++ b/main.c
@@ -22,11 +22,19 @@

static bool match_profile_output(struct kanshi_profile_output *output,
		struct kanshi_head *head) {
	// TODO: improve vendor/model/serial matching
	// Assume the field is empty if it's not set.
	const char *make = head->make ? head->make : "";
	const char *model = head->model ? head->model : "";
	const char *serial_number =
		head->serial_number ? head->serial_number : "";

	char identifier[1024];
	assert(1024 >= strlen(make) + strlen(model) + strlen(serial_number) + 3);
	snprintf(identifier, 1024, "%s %s %s", make, model, serial_number);

	return strcmp(output->name, "*") == 0 ||
		strcmp(output->name, head->name) == 0 ||
		(strchr(output->name, ' ') != NULL &&
		strstr(head->description, output->name) != NULL);
		strcmp(output->name, identifier) == 0;
}

static bool match_profile(struct kanshi_state *state,
@@ -390,9 +398,33 @@ static void head_handle_finished(void *data,
	zwlr_output_head_v1_destroy(head->wlr_head);
	free(head->name);
	free(head->description);
	free(head->make);
	free(head->model);
	free(head->serial_number);
	free(head);
}

void head_handle_make(void *data,
		struct zwlr_output_head_v1 *zwlr_output_head_v1,
		const char *make) {
	struct kanshi_head *head = data;
	head->make = strdup(make);
}

void head_handle_model(void *data,
		struct zwlr_output_head_v1 *zwlr_output_head_v1,
		const char *model) {
	struct kanshi_head *head = data;
	head->model = strdup(model);
}

void head_handle_serial_number(void *data,
		struct zwlr_output_head_v1 *zwlr_output_head_v1,
		const char *serial_number) {
	struct kanshi_head *head = data;
	head->serial_number = strdup(serial_number);
}

static const struct zwlr_output_head_v1_listener head_listener = {
	.name = head_handle_name,
	.description = head_handle_description,
@@ -404,6 +436,9 @@ static const struct zwlr_output_head_v1_listener head_listener = {
	.transform = head_handle_transform,
	.scale = head_handle_scale,
	.finished = head_handle_finished,
	.make = head_handle_make,
	.model = head_handle_model,
	.serial_number = head_handle_serial_number,
};

static void output_manager_handle_head(void *data,
@@ -459,7 +494,7 @@ static void registry_handle_global(void *data, struct wl_registry *registry,

	if (strcmp(interface, zwlr_output_manager_v1_interface.name) == 0) {
		state->output_manager = wl_registry_bind(registry, name,
			&zwlr_output_manager_v1_interface, 1);
			&zwlr_output_manager_v1_interface, 2);
		zwlr_output_manager_v1_add_listener(state->output_manager,
			&output_manager_listener, state);
	}
-- 
2.35.1
Details
Message ID
<svwhIAAZVoVYkwcgdghrt3_0ku8rflUp5BVKYaqv_a1IdQuU0WKN8P2pcwYJyBlP_G7MsEN10hF1fHg6GRuvHS4rduourERjRukfeC_ejpc=@emersion.fr>
In-Reply-To
<20220404144220.94312-3-ivan.oleynikov95@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Slightly edited to use sizeof(identifier) to avoid hardcoding 1024.
Pushed, thanks!
Reply to thread Export thread (mbox)