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:
parent
a358037d3e
commit
53adaa846c
4 changed files with 62 additions and 22 deletions
14
src/bar.rs
14
src/bar.rs
|
@ -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(¢er));
|
content.set_center_widget(Some(¢er));
|
||||||
content.pack_end(&right, false, false, 0);
|
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.add(&content);
|
||||||
|
|
||||||
win.connect_destroy_event(|_, _| {
|
win.connect_destroy_event(|_, _| {
|
||||||
|
@ -48,12 +48,14 @@ fn load_modules(
|
||||||
right: >k::Box,
|
right: >k::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);
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -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()
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,30 +104,36 @@ 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();
|
||||||
|
if self.all_monitors || workspace.output == output_name {
|
||||||
let item = workspace.as_button(&name_map, &ui_tx);
|
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(¤t.name).unwrap();
|
if let Some(item) = button_map.get(¤t.name) {
|
||||||
menubar.remove(item);
|
menubar.remove(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue