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

Support For Niri Workspaces #726

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

Conversation

anant-357
Copy link

@anant-357 anant-357 commented Sep 8, 2024

Hi, please let me know if I've missed something. Resolves #650.

Copy link

@YaLTeR YaLTeR left a comment

Choose a reason for hiding this comment

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

Hi, only commenting on the niri IPC parts. I also clarified these in niri-ipc docs.

let mut conn = Connection::connect().await.unwrap();

let command = Request::Action(Action::FocusWorkspace {
reference: WorkspaceReferenceArg::from_str(name.as_str()).unwrap(),
Copy link

Choose a reason for hiding this comment

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

Since most workspaces don't have names, this should instead focus by Id (not Idx). There's WorkspaceReferenceArg::Id(u64).

Copy link
Author

Choose a reason for hiding this comment

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

The focus method in the WorkspaceClient trait sends a name. So I would need some way to get the id from name. When converting from Niri Workspace struct to Ironbar Workspace struct, if the workspace has no name I set the id as name. Should I change the FromStr for WorkspaceReferenceArg to parse id instead of idx?

Copy link

Choose a reason for hiding this comment

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

It depends on what ironbar gives you, which I'm not familiar with. Index will work only if the correct monitor is focused when you send this request.

Copy link
Owner

Choose a reason for hiding this comment

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

I think it uses name because that was necessary for one of Sway or Hyprland. Using ID is definitely preferable. If necessary, I'd be okay splitting into a FocusById and FocusByName and letting each compositor impl pick the best case.

src/clients/compositor/niri.rs Outdated Show resolved Hide resolved
src/clients/compositor/niri.rs Outdated Show resolved Hide resolved
@anant-357 anant-357 marked this pull request as draft September 9, 2024 07:59
@JakeStanger
Copy link
Owner

Appreciate the hard work here, big thanks for taking this on. Cheers YaLTeR for reviewing too, means a lot to see the actual dev provide input.

I'm a little busy at the moment so responses from me won't be as fast as I like, but ping me as soon as you need anything from me and I'll look as soon as I can. I'll give it a full review as soon as you're ready.

@anant-357 anant-357 marked this pull request as ready for review September 14, 2024 08:50
Copy link
Owner

@JakeStanger JakeStanger left a comment

Choose a reason for hiding this comment

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

I'm yet to test the PR, but generally this is looking good. There's a few points after an initial scan I'd like addressed, but nothing major. Thanks again for your hard work.

Cargo.toml Outdated
"workspaces+sway" = ["workspaces", "sway"]
"workspaces+hyprland" = ["workspaces", "hyprland"]
"workspaces+niri" = ["workspaces", "niri"]

niri = []
Copy link
Owner

Choose a reason for hiding this comment

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

Niri isn't required as its own feature here. Sway has its own because of the sway-mode module, and hyprland is the name of the Hyprland client crate.

impl WorkspaceClient for Client {
fn focus(&self, name: String) -> Result<()> {
await_sync(async {
let mut conn = Connection::connect().await.unwrap();
Copy link
Owner

Choose a reason for hiding this comment

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

Can all unwraps be replaced by better error handling please. Generally, errors should be cleanly handled by either returning an Err or logging an error and cleanly returning. In rare cases where you absolutely do not expect it to fail, use expect and give a message of why it is expected to never fail.

fn subscribe_workspace_change(
&self,
) -> tokio::sync::broadcast::Receiver<super::WorkspaceUpdate> {
let (tx, rx) = channel(32);
Copy link
Owner

Choose a reason for hiding this comment

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

I prefer to include part of the namespace when creating channels so it's immediatley obvious what kind:

Suggested change
let (tx, rx) = channel(32);
let (tx, rx) = broadcast::channel(32);

let event_niri = event_listener().unwrap();
let events = match event_niri {
Event::WorkspacesChanged { workspaces } => {
// Niri only has a WorkspacesChanged Event and Ironbar has 4 events which have to be handled: Add, Remove, Rename and Move. The way I am handling this here is by keeping a previous state of workspaces and comparing with the new state for changes. To do this efficiently, first I sort the new workspace state based on id. Then I do a linear scan on the states(old and new) togethor. At the end, I over write the old workspace state with the new one. Because of this, on the next event, the old workspace state is already sorted.
Copy link
Owner

Choose a reason for hiding this comment

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

Appreciate the comment but this is a very long line - can it be split across a few lines pls

src/clients/compositor/niri.rs Outdated Show resolved Hide resolved
for event in events {
send!(tx, event);
}
std::thread::sleep(Duration::from_millis(30));
Copy link
Owner

Choose a reason for hiding this comment

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

As you are inside an async block, you should use Tokio's sleep to avoid blocking the thread.

Copy link
Owner

Choose a reason for hiding this comment

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

As this is all compositor-focused I would prefer if all this code was under the compositor module for now. Happy to have a niri module with a couple of files in there.

request: Request,
) -> io::Result<(Reply, impl FnMut() -> io::Result<Event> + '_)> {
let Self(stream) = self;
let mut buf = serde_json::to_string(&request).unwrap();
Copy link
Owner

Choose a reason for hiding this comment

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

In cases like this, if you return a color_eyre::Result you should be able to automatically use the ? operator despite mixing error types.

@JakeStanger JakeStanger added this to the 0.17.0 milestone Nov 4, 2024
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.

Support Niri out of the box
3 participants