1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-01 10:41:03 +02:00

feat(workspaces): support for toggling showing workspaces for all monitors

This commit is contained in:
Jake Stanger 2022-08-14 16:23:41 +01:00
parent a358037d3e
commit 53adaa846c
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
4 changed files with 62 additions and 22 deletions

View file

@ -5,7 +5,7 @@ use gtk::gdk::Monitor;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Orientation}; 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(); let win = ApplicationWindow::builder().application(app).build();
setup_layer_shell(&win, monitor, &config.position); 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(&center)); content.set_center_widget(Some(&center));
content.pack_end(&right, false, false, 0); content.pack_end(&right, false, false, 0);
load_modules(&left, &center, &right, app, config); load_modules(&left, &center, &right, app, config, monitor_name);
win.add(&content); win.add(&content);
win.connect_destroy_event(|_, _| { win.connect_destroy_event(|_, _| {
@ -48,12 +48,14 @@ fn load_modules(
right: &gtk::Box, right: &gtk::Box,
app: &Application, app: &Application,
config: Config, config: Config,
output_name: &str
) { ) {
if let Some(modules) = config.left { if let Some(modules) = config.left {
let info = ModuleInfo { let info = ModuleInfo {
app, app,
location: ModuleLocation::Left, location: ModuleLocation::Left,
bar_position: &config.position bar_position: &config.position,
output_name
}; };
add_modules(left, modules, info); add_modules(left, modules, info);
@ -63,7 +65,8 @@ fn load_modules(
let info = ModuleInfo { let info = ModuleInfo {
app, app,
location: ModuleLocation::Center, location: ModuleLocation::Center,
bar_position: &config.position bar_position: &config.position,
output_name
}; };
add_modules(center, modules, info); add_modules(center, modules, info);
@ -73,7 +76,8 @@ fn load_modules(
let info = ModuleInfo { let info = ModuleInfo {
app, app,
location: ModuleLocation::Right, location: ModuleLocation::Right,
bar_position: &config.position bar_position: &config.position,
output_name
}; };
add_modules(right, modules, info); add_modules(right, modules, info);

View file

@ -11,6 +11,14 @@ use crate::style::load_css;
use dirs::config_dir; use dirs::config_dir;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{gdk, Application}; use gtk::{gdk, Application};
use ksway::client::Client;
use ksway::IpcCommand;
use serde::Deserialize;
#[derive(Deserialize)]
struct SwayOutput {
name: String,
}
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -18,7 +26,11 @@ async fn main() {
.application_id("dev.jstanger.waylandbar") .application_id("dev.jstanger.waylandbar")
.build(); .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::<Vec<SwayOutput>>(&outputs).expect("Failed to deserialize outputs message from Sway IPC");
app.connect_activate(move |app| {
let config = Config::load().unwrap_or_default(); let config = Config::load().unwrap_or_default();
// TODO: Better logging (https://crates.io/crates/tracing) // TODO: Better logging (https://crates.io/crates/tracing)
@ -30,12 +42,13 @@ async fn main() {
let num_monitors = display.n_monitors(); let num_monitors = display.n_monitors();
for i in 0..num_monitors { for i in 0..num_monitors {
let monitor = display.monitor(i).unwrap(); 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| { let config = config.monitors.as_ref().map_or(&config, |monitor_config| {
monitor_config.get(i as usize).unwrap_or(&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() let style_path = config_dir()

View file

@ -30,7 +30,8 @@ pub enum ModuleLocation {
pub struct ModuleInfo<'a> { pub struct ModuleInfo<'a> {
pub app: &'a Application, pub app: &'a Application,
pub location: ModuleLocation, pub location: ModuleLocation,
pub bar_position: &'a BarPosition pub bar_position: &'a BarPosition,
pub output_name: &'a str
} }
pub trait Module<W> pub trait Module<W>

View file

@ -11,7 +11,14 @@ use tokio::task::spawn_blocking;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct WorkspacesModule { pub struct WorkspacesModule {
pub(crate) name_map: Option<HashMap<String, String>>, name_map: Option<HashMap<String, String>>,
#[serde(default = "default_false")]
all_monitors: bool,
}
const fn default_false() -> bool {
false
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -19,7 +26,7 @@ struct Workspace {
name: String, name: String,
focused: bool, focused: bool,
// num: i32, // num: i32,
// output: String, output: String,
} }
impl Workspace { impl Workspace {
@ -53,14 +60,23 @@ struct WorkspaceEvent {
} }
impl Module<gtk::Box> for WorkspacesModule { impl Module<gtk::Box> 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 mut sway = Client::connect().unwrap();
let container = gtk::Box::new(Orientation::Horizontal, 0); let container = gtk::Box::new(Orientation::Horizontal, 0);
let workspaces = { let workspaces = {
let raw = sway.ipc(IpcCommand::GetWorkspaces).unwrap(); let raw = sway.ipc(IpcCommand::GetWorkspaces).unwrap();
serde_json::from_slice::<Vec<Workspace>>(&raw).unwrap() let workspaces = serde_json::from_slice::<Vec<Workspace>>(&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(); let name_map = self.name_map.unwrap_or_default();
@ -88,29 +104,35 @@ impl Module<gtk::Box> for WorkspacesModule {
{ {
let menubar = container.clone(); let menubar = container.clone();
let output_name = info.output_name.to_string();
rx.attach(None, move |event| { rx.attach(None, move |event| {
match event.change.as_str() { match event.change.as_str() {
"focus" => { "focus" => {
let old = event.old.unwrap(); let old = event.old.unwrap();
let old_button = button_map.get(&old.name).unwrap(); if let Some(old_button) = button_map.get(&old.name) {
old_button.style_context().remove_class("focused"); old_button.style_context().remove_class("focused");
}
let new = event.current.unwrap(); let new = event.current.unwrap();
let new_button = button_map.get(&new.name).unwrap(); if let Some(new_button) = button_map.get(&new.name) {
new_button.style_context().add_class("focused"); new_button.style_context().add_class("focused");
}
} }
"init" => { "init" => {
let workspace = event.current.unwrap(); 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(); item.show();
menubar.add(&item); menubar.add(&item);
button_map.insert(workspace.name, item); button_map.insert(workspace.name, item);
}
} }
"empty" => { "empty" => {
let current = event.current.unwrap(); let current = event.current.unwrap();
let item = button_map.get(&current.name).unwrap(); if let Some(item) = button_map.get(&current.name) {
menubar.remove(item); menubar.remove(item);
}
} }
_ => {} _ => {}
} }