sway
sway copied to clipboard
Feature request: allow matching outputs by both port and model name
I would like to match an output by it's port name and it's model name.
Something like:
output DP-1 'Acer Technologies Acer KG241 P 0x0000F372' mode 1920x1080@144Hz
Currently, one can only match an output with either the port name or the model name, but not both.
The use case for this, is that I have a monitor that supports different refresh rates in DisplayPort compared to HDMI and this monitor reports incorrect preferred modes. if I set the mode with the model only, then be incorrect when I use the monitor through HDMI. The same goes with the port only, what if I plug another DisplayPort monitor?
See https://github.com/swaywm/sway/issues/6391 for more context.
Hello again, I'm willing to give it a try and to implement this feature myself.
I've been navigating the code and I stumbled this function:
void apply_output_config_to_outputs(struct output_config *oc) {
// Try to find the output container and apply configuration now. If
// this is during startup then there will be no container and config
// will be applied during normal "new output" event from wlroots.
bool wildcard = strcmp(oc->name, "*") == 0;
char id[128];
struct sway_output *sway_output, *tmp;
wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
char *name = sway_output->wlr_output->name;
output_get_identifier(id, sizeof(id), sway_output);
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
struct output_config *current = get_output_config(id, sway_output);
if (!current) {
// No stored output config matched, apply oc directly
sway_log(SWAY_DEBUG, "Applying oc directly");
current = new_output_config(oc->name);
merge_output_config(current, oc);
}
apply_output_config(current, sway_output);
free_output_config(current);
if (!wildcard) {
// Stop looking if the output config isn't applicable to all
// outputs
break;
}
}
}
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
cursor_rebase(seat->cursor);
}
}
If I understood correctly, the matching occurs here:
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
The way this is being done doesn't allow for matching both the output name and ID. I'm thinking of several ways this can be implemented but I'm not familiar with the project.
Anyone can give me any leads?
Thanks in advance.
We'd first need to decide a syntax for this, I guess. I'm not a fan of what @itaranto suggested because it's ambiguous whether or not the second argument is an output ID or an output sub-command.
Maybe a flag (--match-identifier="Acer Technologies Acer KG241 P 0x0000F372"
) would be a bit better. Ideas welcome.
Then, we'd need to add a few more fields to struct output_config
, e.g. id
to match the ID, and use them in the matching logic.
We'd first need to decide a syntax for this, I guess. I'm not a fan of what @itaranto suggested because it's ambiguous whether or not the second argument is an output ID or an output sub-command.
Maybe a flag (
--match-identifier="Acer Technologies Acer KG241 P 0x0000F372"
) would be a bit better. Ideas welcome.Then, we'd need to add a few more fields to
struct output_config
, e.g.id
to match the ID, and use them in the matching logic.
Yes, adding an argument will be ambiguous.
How about adding some special syntax to the name/ID string? This way the number of parameters wouldn't change and it should be backwards compatible.
The syntax could be something like:
-
"DP-1: Some Company ABC123 0x00000000"
to match both. -
"DP-1"
to match only the name (same as before). -
"Some Company ABC123 0x00000000"
to match only the ID (same as before).
Doing things like this is much easier after the rework done in #5629. The matching logic becomes centralized in a single place so it's easy to do this, glob matching or even complex boolean stuff (e.g., displays called "LG" that are not on display port links).
How complex or not matching should be is a feature discussion, but if there's interest, as I've offered before, I can resubmit #5629 without the glob matching itself. Glob matching is only a one line change on top of the code refactor.
Would it be better to match by output and resolution? Or perhaps even match only by resolution!
That way, it won't matter what brand/model of monitor you plug in, it just finds the config for a matching resolution and applies that.
I'm using kanshi
for this, at the cost of a combinatorial explosion in configurations (i.e. one for laptop screen only, one for desktop monitor only, one for both on, etc; X2 for every new on/off combination when adding an input like XREAL AR glasses).
This lets you configure by semantic identifier name ("Some Monitor Inc" rather than output name "DP-2"), and have this automatically applied on hotswap. However it's then cumbersome to perform configuration that relies on the output name (background image AFAICT can only be set by the output name) - for this I'm having to introspect on get_outputs and script updates depending on what is detected. An official solution would be great.
#5629 mentions shikane
- looks like this offers most of the functionality discussed in this issue.