multibg-wayland/src/compositors/niri2505.rs
2025-08-18 13:05:11 -07:00

79 lines
2.8 KiB
Rust

use std::io;
use log::debug;
use niri_ipc_25_5_1::{socket::Socket, Event, Request, Response, Workspace};
use super::{CompositorInterface, EventSender, WorkspaceVisible};
pub struct NiriConnectionTask {}
impl NiriConnectionTask {
pub fn new() -> Self {
NiriConnectionTask {}
}
}
impl CompositorInterface for NiriConnectionTask {
fn request_visible_workspaces(&mut self) -> Vec<WorkspaceVisible> {
request_workspaces().into_iter()
.filter(|w| w.is_active)
.map(|workspace| WorkspaceVisible {
output: workspace.output.unwrap_or_default(),
workspace_name: workspace.name
.unwrap_or_else(|| format!("{}", workspace.idx)),
workspace_number: workspace.idx.into(),
})
.collect()
}
fn subscribe_event_loop(self, event_sender: EventSender) {
let mut workspaces_state = request_workspaces();
let mut callback = request_event_stream();
while let Ok(event) = callback() {
match event {
Event::WorkspaceActivated { id, focused: _ } => {
debug!("Niri event: workspace id {id} activated");
let visible_workspace =
find_workspace(&workspaces_state, id);
event_sender.send(visible_workspace);
},
Event::WorkspacesChanged { workspaces } => {
debug!("Niri event: workspaces changed: {workspaces:?}");
workspaces_state = workspaces
},
_ => {},
}
}
}
}
fn find_workspace(workspaces: &[Workspace], id: u64) -> WorkspaceVisible {
let workspace = workspaces.iter()
.find(|workspace| workspace.id == id)
.unwrap_or_else(|| panic!("Unknown niri workspace id {id}"));
let workspace_name = workspace.name.clone()
.unwrap_or_else(|| format!("{}", workspace.idx));
let workspace_number: i32 = workspace.idx.into();
let output = workspace.output.clone().unwrap_or_default();
WorkspaceVisible { output, workspace_name, workspace_number }
}
fn request_event_stream() -> impl FnMut() -> Result<Event, io::Error> {
let mut socket = Socket::connect().expect("failed to connect to niri socket");
let Ok(Ok(Response::Handled)) = socket.send(Request::EventStream) else {
panic!("failed to subscribe to event stream");
};
socket.read_events()
}
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")
.expect("niri workspace query failed");
let Response::Workspaces(workspaces) = response else {
panic!("unexpected response from niri");
};
workspaces
}