Skip to content
This repository has been archived by the owner on Sep 15, 2021. It is now read-only.

Add IPC method to select a profile #108

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

ericonr
Copy link
Contributor

@ericonr ericonr commented Jul 25, 2021

This "works", in the sense that the server receives the request and applies the profile. However, it seems that it immediately triggers a "detected change" event, and the server applies the old profile again:

applying profile 'home_desk'
applying profile output 'LG HDR WFHD' on connected head 'DP-3'
applying profile output 'eDP-1' on connected head 'eDP-1'
running commands for configuration 'home_desk'
configuration for profile 'home_desk' applied <------ HERE is where I call kanshictl
loading profile only_external
applying profile 'only_external'
applying profile output 'LG HDR WFHD' on connected head 'DP-3'
applying profile output 'eDP-1' on connected head 'eDP-1'
running commands for configuration 'only_external'
configuration for profile 'only_external' applied
applying profile 'home_desk' <------- THIS starts immediately
applying profile output 'LG HDR WFHD' on connected head 'DP-3'
applying profile output 'eDP-1' on connected head 'eDP-1'
running commands for configuration 'home_desk'
configuration for profile 'home_desk' applied

I'm looking into the code to try and understand how to make this not happen, but would definitely appreciate tips on where to look :)

I hope my approach is correct, too.

Harmless, because it was using size of a pointer, which will always be
the same, but still confusing to read. Using `sizeof *matches` makes it
so any change to the type of `matches` will keep the expression correct.
@ericonr
Copy link
Contributor Author

ericonr commented Jul 26, 2021

static void output_manager_handle_done(void *data,
		struct zwlr_output_manager_v1 *manager, uint32_t serial) {
	struct kanshi_state *state = data;
	state->serial = serial;

	//try_apply_profiles(state);
}

makes kanshi not do anything when it's started, but also makes it behave predictably when it receives kanshictl profile <> commands.

@ericonr
Copy link
Contributor Author

ericonr commented Jul 26, 2021

Ok, I think my latest commit fixes it. I left a few questions in the commit message about the implementation.

@emersion
Copy link
Owner

emersion commented Jul 26, 2021

The compositor will broadcast events followed by a done event when the output configuration changes. When applying a profile we trigger a configuration change.

What I originally thought of was that the profile names would act as a tie-breaker. Setting a profile name would add a new condition to match_profile, something like

if (state->selected_profile_name != NULL && profile->name != NULL &&
        strcmp(state->selected_profile_name, profile->name) != 0) {
    return false;
}

So that the normal matching logic still applies, ie.

  • kanchictl switch asdf doesn't apply asdf when asdf doesn't make sense given the currently plugged in outputs
  • It's possible to define multiple profiles with the same name and with a different set of outputs

To implement this, the "currently selected profile name" would need to be saved in state (in the example code above, in state->selected_profile_name).

I'm open to other ideas though.

@ericonr
Copy link
Contributor Author

ericonr commented Jul 26, 2021

So basically you would just have me update the current name, then call try_all_profiles? I like that idea, makes the whole thing more deterministic.

Would you prefer kanshictl switch over kanshictl profile?

@emersion
Copy link
Owner

So basically you would just have me update the current name, then call try_all_profiles?

Yup!

Would you prefer kanshictl switch over kanshictl profile?

I'd prefer to pick a subcommand name that describes an action. switch may not be that great, because it may not actually switch anything. Maybe set-profile?

This allows us to add an extra constraint for try_apply_profiles, which
now takes the selected profile name into account.
@ericonr
Copy link
Contributor Author

ericonr commented Jul 26, 2021

I wonder if current and pending names wouldn't be necessary? Otherwise using a name that doesn't exist would break any further transitions.

And using set-profile even once would mean that automatic transitions would now need to also match the profile name. Maybe the manual should document that reload can be used to reset things?

@ericonr
Copy link
Contributor Author

ericonr commented Jul 26, 2021

Maybe we should try and report an error back to kanshictl if setting the profile fails...

@emersion
Copy link
Owner

Maybe we should try and report an error back to kanshictl if setting the profile fails...

Sounds sensible.

Also adding something like kanshictl set-profile "*" to reset to "match any profile name" would be handy. (Wildcard char subject to bikeshedding, something like - might be better to avoid shell quoting.)

Rework how varlink_connection_call is called so the logic is used by all
methods. Uses method_name as a sign that argv[1] was matched by some
known method.
@ericonr
Copy link
Contributor Author

ericonr commented Jul 26, 2021

(Wildcard char subject to bikeshedding, something like - might be better to avoid shell quoting.)

Would have to forbid profiles named -, then :p

But I like the idea.

@@ -425,6 +429,10 @@ static bool try_apply_profiles(struct kanshi_state *state) {
assert(wl_list_length(&state->heads) <= HEADS_MAX);
// matches[i] gives the kanshi_profile_output for the i-th head
struct kanshi_profile_output *matches[HEADS_MAX];
if (state->current_profile && match_profile(state, state->current_profile, matches)) {
Copy link
Owner

Choose a reason for hiding this comment

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

Hm, I don't understand what this does

@@ -36,7 +36,12 @@ static bool match_profile(struct kanshi_state *state,
return false;
}

memset(matches, 0, HEADS_MAX * sizeof(struct kanshi_head *));
memset(matches, 0, HEADS_MAX * sizeof *matches);
Copy link
Owner

Choose a reason for hiding this comment

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

Style: missing parentheses after sizeof

ipc.c Show resolved Hide resolved
@ericonr
Copy link
Contributor Author

ericonr commented Aug 7, 2021

So, I've been dog fooding another version of this for a while now, which implements the idea in #108 (comment)

I am, however, hitting an UX issue because of it.

My config is:

profile home_desk {
	output "LG HDR WFHD" enable mode 2560x1080 position 0,0
	output eDP-1 enable scale 1.1 position 0,1080
}

profile only_external {
	output "LG HDR WFHD" enable mode 2560x1080 position 0,0
	output eDP-1 disable
}

profile only_internal {
	output "LG HDR WFHD" disable
	output eDP-1 enable scale 1.0 position 0,0
}

profile out_and_about {
	output eDP-1 enable scale 1 position 0,0
}

I start with home_desk, but will often switch to only_external; if I switch back to home_desk, and then remove the external monitor (which should trigger out_and_about), it will instead do nothing, because it can't match a profile with the name home_desk to something that only has the internal monitor. This is even worse if I leave it in only_external.

I didn't like this experience, and I think I prefer the style where set-profile is something you set once to pick a profile for that particular monitor combination, and any change in output availability will return to the normal matching logic.

That's what the code you asked about in #108 (review) implemented: without that, selecting a profile led to kanshi moving to it, then getting a wayland callback, and moving back to the first match in the config (as described in #108 (comment)); with that, it makes sure not to override a manually selected profile (which was set via the set-profile RPC call) when the callback is called, and therefore doesn't restore the first match in the config.

@emersion
Copy link
Owner

emersion commented Aug 12, 2021

As discussed on IRC, two potential solutions:

  • Make set-profile "one-off": applies the profile with the specified name, and does nothing more. This has the downside of being fragile:
    • Requires a hack to avoid re-applying a different profile when the notification that the provided profile has been applied is sent by the compositor, but this is racy with a real hotplug.
    • Any little change in the output configuration (e.g. user executes a swaymsg output … command) will re-apply a different profile.
  • Make set-profile indicate a preference: if a profile with the specified name can be found and is applicable, use it, otherwise fallback to any other profile. The preference sticks around until another set-profile command is issued.

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

Successfully merging this pull request may close these issues.

None yet

2 participants