Change niri event subscription loop to cache the state of current workspaces

This commit is contained in:
Gergő Sályi 2025-04-09 19:23:29 +02:00
parent e64359806c
commit bcb60ea839

View file

@ -1,6 +1,6 @@
use std::io;
use super::{CompositorInterface, WorkspaceVisible, EventSender}; use super::{CompositorInterface, WorkspaceVisible, EventSender};
use niri_ipc::{socket::Socket, Event, Request, Response}; use niri_ipc::{socket::Socket, Event, Request, Response, Workspace};
pub struct NiriConnectionTask {} pub struct NiriConnectionTask {}
@ -8,60 +8,68 @@ impl NiriConnectionTask {
pub fn new() -> Self { pub fn new() -> Self {
NiriConnectionTask {} NiriConnectionTask {}
} }
fn query_workspace(&self, id: u64) -> (String, String) {
if let Ok((Ok(Response::Workspaces(workspaces)), _)) = Socket::connect()
.expect("failed to connect to niri socket")
.send(Request::Workspaces)
{
if let Some(workspace) = workspaces.into_iter().find(|w| w.id == id) {
return (
workspace.name.unwrap_or_else(|| format!("{}", workspace.idx)),
workspace.output.unwrap_or_else(String::new),
);
}
panic!("unknown workspace id");
} else {
panic!("niri workspace query failed");
}
}
} }
impl CompositorInterface for NiriConnectionTask { impl CompositorInterface for NiriConnectionTask {
fn request_visible_workspaces(&mut self) -> Vec<WorkspaceVisible> { fn request_visible_workspaces(&mut self) -> Vec<WorkspaceVisible> {
if let Ok((Ok(Response::Workspaces(workspaces)), _)) = Socket::connect() request_workspaces().into_iter()
.expect("failed to connect to niri socket") .filter(|w| w.is_active)
.send(Request::Workspaces) .map(|workspace| WorkspaceVisible {
{ output: workspace.output.unwrap_or_default(),
workspaces workspace_name: workspace.name
.into_iter() .unwrap_or_else(|| format!("{}", workspace.idx)),
.filter(|w| w.is_active) })
.map(|workspace| WorkspaceVisible { .collect()
output: workspace.output.unwrap_or_default(),
workspace_name: workspace.name
.unwrap_or_else(|| format!("{}", workspace.idx)),
})
.collect()
} else {
panic!("unable to retrieve niri workspaces")
}
} }
fn subscribe_event_loop(self, event_sender: EventSender) { fn subscribe_event_loop(self, event_sender: EventSender) {
if let Ok((Ok(Response::Handled), mut callback)) = Socket::connect() let mut workspaces_state = request_workspaces();
.expect("failed to connect to niri socket") let mut callback = request_event_stream();
.send(Request::EventStream) while let Ok(event) = callback() {
{ match event {
while let Ok(event) = callback() { Event::WorkspaceActivated { id, focused: _ } => {
if let Event::WorkspaceActivated { id, focused: _ } = event { let visible_workspace =
let (workspace_name, output) = self.query_workspace(id); find_workspace(&workspaces_state, id);
event_sender.send(WorkspaceVisible { event_sender.send(visible_workspace);
output, },
workspace_name, Event::WorkspacesChanged { workspaces } => {
}); workspaces_state = workspaces
} },
_ => {},
} }
} else {
panic!("failed to subscribe to event stream");
} }
} }
} }
fn find_workspace(workspaces: &[Workspace], id: u64) -> WorkspaceVisible {
let workspace = workspaces.iter()
.find(|workspace| workspace.id == id)
.expect("Unknown niri workspace id {id}");
let workspace_name = workspace.name.clone()
.unwrap_or_else(|| format!("{}", workspace.idx));
let output = workspace.output.clone().unwrap_or_default();
WorkspaceVisible { output, workspace_name }
}
fn request_event_stream() -> impl FnMut() -> Result<Event, io::Error> {
let Ok((Ok(Response::Handled), callback)) = Socket::connect()
.expect("failed to connect to niri socket")
.send(Request::EventStream)
else {
panic!("failed to subscribe to event stream");
};
callback
}
fn request_workspaces() -> Vec<Workspace> {
let response = Socket::connect()
.expect("failed to connect to niri socket")
.send(Request::Workspaces)
.expect("failed to send niri ipc request")
.0
.expect("niri workspace query failed");
let Response::Workspaces(workspaces) = response else {
panic!("unexpected response from niri");
};
workspaces
}