mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-08-17 14:51:04 +02:00
feat(workspaces): hyprland support
Resolves #18. The bar will now automatically detect whether running under Sway or Hyprland and use the correct IPC client depending.
This commit is contained in:
parent
a79900d842
commit
6e5d0c1e8c
8 changed files with 585 additions and 177 deletions
148
src/clients/compositor/sway.rs
Normal file
148
src/clients/compositor/sway.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
use super::{Workspace, WorkspaceClient, WorkspaceUpdate};
|
||||
use crate::await_sync;
|
||||
use crate::error::ERR_CHANNEL_SEND;
|
||||
use async_once::AsyncOnce;
|
||||
use color_eyre::Report;
|
||||
use futures_util::StreamExt;
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::Arc;
|
||||
use swayipc_async::{Connection, Event, EventType, Node, WorkspaceChange, WorkspaceEvent};
|
||||
use tokio::spawn;
|
||||
use tokio::sync::broadcast::{channel, Receiver, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::{info, trace};
|
||||
|
||||
pub struct SwayEventClient {
|
||||
workspace_tx: Sender<WorkspaceUpdate>,
|
||||
_workspace_rx: Receiver<WorkspaceUpdate>,
|
||||
}
|
||||
|
||||
impl SwayEventClient {
|
||||
fn new() -> Self {
|
||||
let (workspace_tx, workspace_rx) = channel(16);
|
||||
|
||||
{
|
||||
let workspace_tx = workspace_tx.clone();
|
||||
spawn(async move {
|
||||
let client = Connection::new().await?;
|
||||
info!("Sway IPC subscription client connected");
|
||||
|
||||
let event_types = [EventType::Workspace];
|
||||
|
||||
let mut events = client.subscribe(event_types).await?;
|
||||
|
||||
while let Some(event) = events.next().await {
|
||||
trace!("event: {:?}", event);
|
||||
if let Event::Workspace(ev) = event? {
|
||||
workspace_tx.send(WorkspaceUpdate::from(*ev))?;
|
||||
};
|
||||
}
|
||||
|
||||
Ok::<(), Report>(())
|
||||
});
|
||||
}
|
||||
|
||||
Self {
|
||||
workspace_tx,
|
||||
_workspace_rx: workspace_rx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WorkspaceClient for SwayEventClient {
|
||||
fn focus(&self, id: String) -> color_eyre::Result<()> {
|
||||
await_sync(async move {
|
||||
let client = get_client().await;
|
||||
let mut client = client.lock().await;
|
||||
client.run_command(format!("workspace {id}")).await
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn subscribe_workspace_change(&self) -> Receiver<WorkspaceUpdate> {
|
||||
let rx = self.workspace_tx.subscribe();
|
||||
|
||||
{
|
||||
let tx = self.workspace_tx.clone();
|
||||
await_sync(async {
|
||||
let client = get_client().await;
|
||||
let mut client = client.lock().await;
|
||||
|
||||
let workspaces = client
|
||||
.get_workspaces()
|
||||
.await
|
||||
.expect("Failed to get workspaces");
|
||||
let event =
|
||||
WorkspaceUpdate::Init(workspaces.into_iter().map(Workspace::from).collect());
|
||||
|
||||
tx.send(event).expect(ERR_CHANNEL_SEND);
|
||||
});
|
||||
}
|
||||
|
||||
rx
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref CLIENT: AsyncOnce<Arc<Mutex<Connection>>> = AsyncOnce::new(async {
|
||||
let client = Connection::new()
|
||||
.await
|
||||
.expect("Failed to connect to Sway socket");
|
||||
Arc::new(Mutex::new(client))
|
||||
});
|
||||
static ref SUB_CLIENT: SwayEventClient = SwayEventClient::new();
|
||||
}
|
||||
|
||||
/// Gets the sway IPC client
|
||||
async fn get_client() -> Arc<Mutex<Connection>> {
|
||||
let client = CLIENT.get().await;
|
||||
Arc::clone(client)
|
||||
}
|
||||
|
||||
/// Gets the sway IPC event subscription client
|
||||
pub fn get_sub_client() -> &'static SwayEventClient {
|
||||
&SUB_CLIENT
|
||||
}
|
||||
|
||||
impl From<Node> for Workspace {
|
||||
fn from(node: Node) -> Self {
|
||||
Self {
|
||||
id: node.id.to_string(),
|
||||
name: node.name.unwrap_or_default(),
|
||||
monitor: node.output.unwrap_or_default(),
|
||||
focused: node.focused,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<swayipc_async::Workspace> for Workspace {
|
||||
fn from(workspace: swayipc_async::Workspace) -> Self {
|
||||
Self {
|
||||
id: workspace.id.to_string(),
|
||||
name: workspace.name,
|
||||
monitor: workspace.output,
|
||||
focused: workspace.focused,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WorkspaceEvent> for WorkspaceUpdate {
|
||||
fn from(event: WorkspaceEvent) -> Self {
|
||||
match event.change {
|
||||
WorkspaceChange::Init => {
|
||||
Self::Add(event.current.expect("Missing current workspace").into())
|
||||
}
|
||||
WorkspaceChange::Empty => {
|
||||
Self::Remove(event.current.expect("Missing current workspace").into())
|
||||
}
|
||||
WorkspaceChange::Focus => Self::Focus {
|
||||
old: event.old.expect("Missing old workspace").into(),
|
||||
new: event.current.expect("Missing current workspace").into(),
|
||||
},
|
||||
WorkspaceChange::Move => {
|
||||
Self::Move(event.current.expect("Missing current workspace").into())
|
||||
}
|
||||
_ => Self::Update(event.current.expect("Missing current workspace").into()),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue