diff --git a/src/bar.rs b/src/bar.rs index a6e9614..9d9c768 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -5,7 +5,7 @@ use gtk::gdk::Monitor; use gtk::prelude::*; use gtk::{Application, ApplicationWindow, Orientation}; -pub fn create_bar(app: &Application, monitor: &Monitor, config: Config) { +pub fn create_bar(app: &Application, monitor: &Monitor, monitor_name: &str, config: Config) { let win = ApplicationWindow::builder().application(app).build(); setup_layer_shell(&win, monitor, &config.position); @@ -31,7 +31,7 @@ pub fn create_bar(app: &Application, monitor: &Monitor, config: Config) { content.set_center_widget(Some(¢er)); content.pack_end(&right, false, false, 0); - load_modules(&left, ¢er, &right, app, config); + load_modules(&left, ¢er, &right, app, config, monitor_name); win.add(&content); win.connect_destroy_event(|_, _| { @@ -48,12 +48,14 @@ fn load_modules( right: >k::Box, app: &Application, config: Config, + output_name: &str ) { if let Some(modules) = config.left { let info = ModuleInfo { app, location: ModuleLocation::Left, - bar_position: &config.position + bar_position: &config.position, + output_name }; add_modules(left, modules, info); @@ -63,7 +65,8 @@ fn load_modules( let info = ModuleInfo { app, location: ModuleLocation::Center, - bar_position: &config.position + bar_position: &config.position, + output_name }; add_modules(center, modules, info); @@ -73,7 +76,8 @@ fn load_modules( let info = ModuleInfo { app, location: ModuleLocation::Right, - bar_position: &config.position + bar_position: &config.position, + output_name }; add_modules(right, modules, info); diff --git a/src/main.rs b/src/main.rs index 1b4d74a..65004de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,14 @@ use crate::style::load_css; use dirs::config_dir; use gtk::prelude::*; use gtk::{gdk, Application}; +use ksway::client::Client; +use ksway::IpcCommand; +use serde::Deserialize; + +#[derive(Deserialize)] +struct SwayOutput { + name: String, +} #[tokio::main] async fn main() { @@ -18,7 +26,11 @@ async fn main() { .application_id("dev.jstanger.waylandbar") .build(); - app.connect_activate(|app| { + let mut sway_client = Client::connect().expect("Failed to connect to Sway IPC"); + let outputs = sway_client.ipc(IpcCommand::GetOutputs).expect("Failed to get Sway outputs"); + let outputs = serde_json::from_slice::>(&outputs).expect("Failed to deserialize outputs message from Sway IPC"); + + app.connect_activate(move |app| { let config = Config::load().unwrap_or_default(); // TODO: Better logging (https://crates.io/crates/tracing) @@ -30,12 +42,13 @@ async fn main() { let num_monitors = display.n_monitors(); for i in 0..num_monitors { let monitor = display.monitor(i).unwrap(); + let monitor_name = &outputs.get(i as usize).expect("GTK monitor output differs from Sway's").name; let config = config.monitors.as_ref().map_or(&config, |monitor_config| { monitor_config.get(i as usize).unwrap_or(&config) }); - create_bar(app, &monitor, config.clone()); + create_bar(app, &monitor, monitor_name, config.clone()); } let style_path = config_dir() diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 4c670ab..ed0bbbd 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -30,7 +30,8 @@ pub enum ModuleLocation { pub struct ModuleInfo<'a> { pub app: &'a Application, pub location: ModuleLocation, - pub bar_position: &'a BarPosition + pub bar_position: &'a BarPosition, + pub output_name: &'a str } pub trait Module diff --git a/src/modules/workspaces.rs b/src/modules/workspaces.rs index baf3d4c..eb6d6db 100644 --- a/src/modules/workspaces.rs +++ b/src/modules/workspaces.rs @@ -11,7 +11,14 @@ use tokio::task::spawn_blocking; #[derive(Debug, Deserialize, Clone)] pub struct WorkspacesModule { - pub(crate) name_map: Option>, + name_map: Option>, + + #[serde(default = "default_false")] + all_monitors: bool, +} + +const fn default_false() -> bool { + false } #[derive(Deserialize, Debug)] @@ -19,7 +26,7 @@ struct Workspace { name: String, focused: bool, // num: i32, - // output: String, + output: String, } impl Workspace { @@ -53,14 +60,23 @@ struct WorkspaceEvent { } impl Module for WorkspacesModule { - fn into_widget(self, _info: &ModuleInfo) -> gtk::Box { + fn into_widget(self, info: &ModuleInfo) -> gtk::Box { let mut sway = Client::connect().unwrap(); let container = gtk::Box::new(Orientation::Horizontal, 0); let workspaces = { let raw = sway.ipc(IpcCommand::GetWorkspaces).unwrap(); - serde_json::from_slice::>(&raw).unwrap() + let workspaces = serde_json::from_slice::>(&raw).unwrap(); + + if !self.all_monitors { + workspaces + .into_iter() + .filter(|workspace| workspace.output == info.output_name) + .collect() + } else { + workspaces + } }; let name_map = self.name_map.unwrap_or_default(); @@ -88,29 +104,35 @@ impl Module for WorkspacesModule { { let menubar = container.clone(); + let output_name = info.output_name.to_string(); rx.attach(None, move |event| { match event.change.as_str() { "focus" => { let old = event.old.unwrap(); - let old_button = button_map.get(&old.name).unwrap(); - old_button.style_context().remove_class("focused"); + if let Some(old_button) = button_map.get(&old.name) { + old_button.style_context().remove_class("focused"); + } let new = event.current.unwrap(); - let new_button = button_map.get(&new.name).unwrap(); - new_button.style_context().add_class("focused"); + if let Some(new_button) = button_map.get(&new.name) { + new_button.style_context().add_class("focused"); + } } "init" => { let workspace = event.current.unwrap(); - let item = workspace.as_button(&name_map, &ui_tx); + if self.all_monitors || workspace.output == output_name { + let item = workspace.as_button(&name_map, &ui_tx); - item.show(); - menubar.add(&item); - button_map.insert(workspace.name, item); + item.show(); + menubar.add(&item); + button_map.insert(workspace.name, item); + } } "empty" => { let current = event.current.unwrap(); - let item = button_map.get(¤t.name).unwrap(); - menubar.remove(item); + if let Some(item) = button_map.get(¤t.name) { + menubar.remove(item); + } } _ => {} }