2022-08-14 20:40:11 +01:00
|
|
|
use crate::icon;
|
|
|
|
use crate::modules::{Module, ModuleInfo};
|
2022-08-21 23:36:07 +01:00
|
|
|
use crate::sway::{SwayClient, WindowEvent};
|
|
|
|
use color_eyre::Result;
|
2022-08-14 20:40:11 +01:00
|
|
|
use glib::Continue;
|
|
|
|
use gtk::prelude::*;
|
|
|
|
use gtk::{IconTheme, Image, Label, Orientation};
|
2022-08-21 23:36:07 +01:00
|
|
|
use ksway::IpcEvent;
|
2022-08-14 20:40:11 +01:00
|
|
|
use serde::Deserialize;
|
|
|
|
use tokio::task::spawn_blocking;
|
2022-08-21 23:36:07 +01:00
|
|
|
use tracing::error;
|
2022-08-14 20:40:11 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
|
|
pub struct FocusedModule {
|
|
|
|
#[serde(default = "crate::config::default_true")]
|
|
|
|
show_icon: bool,
|
|
|
|
#[serde(default = "crate::config::default_true")]
|
|
|
|
show_title: bool,
|
|
|
|
|
|
|
|
#[serde(default = "default_icon_size")]
|
|
|
|
icon_size: i32,
|
|
|
|
icon_theme: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
const fn default_icon_size() -> i32 {
|
|
|
|
32
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Module<gtk::Box> for FocusedModule {
|
2022-08-21 23:36:07 +01:00
|
|
|
fn into_widget(self, _info: &ModuleInfo) -> Result<gtk::Box> {
|
2022-08-14 20:40:11 +01:00
|
|
|
let icon_theme = IconTheme::new();
|
|
|
|
|
|
|
|
if let Some(theme) = self.icon_theme {
|
|
|
|
icon_theme.set_custom_theme(Some(&theme));
|
|
|
|
}
|
|
|
|
|
|
|
|
let container = gtk::Box::new(Orientation::Horizontal, 5);
|
|
|
|
|
|
|
|
let icon = Image::builder().name("icon").build();
|
|
|
|
let label = Label::builder().name("label").build();
|
|
|
|
|
|
|
|
container.add(&icon);
|
|
|
|
container.add(&label);
|
|
|
|
|
2022-08-21 23:36:07 +01:00
|
|
|
let mut sway = SwayClient::connect()?;
|
2022-08-14 20:40:11 +01:00
|
|
|
|
2022-08-21 23:36:07 +01:00
|
|
|
let srx = sway.subscribe(vec![IpcEvent::Window])?;
|
2022-08-14 20:40:11 +01:00
|
|
|
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
|
|
|
|
2022-08-21 23:36:07 +01:00
|
|
|
let focused = sway
|
|
|
|
.get_open_windows()?
|
2022-08-14 20:40:11 +01:00
|
|
|
.into_iter()
|
|
|
|
.find(|node| node.focused);
|
|
|
|
|
|
|
|
if let Some(focused) = focused {
|
2022-08-21 23:36:07 +01:00
|
|
|
tx.send(focused)?;
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
spawn_blocking(move || loop {
|
|
|
|
while let Ok((_, payload)) = srx.try_recv() {
|
2022-08-21 23:36:07 +01:00
|
|
|
match serde_json::from_slice::<WindowEvent>(&payload) {
|
|
|
|
Ok(payload) => {
|
|
|
|
let update = match payload.change.as_str() {
|
|
|
|
"focus" => true,
|
|
|
|
"title" => payload.container.focused,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if update {
|
|
|
|
tx.send(payload.container)
|
|
|
|
.expect("Failed to sendf focus update");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(err) => error!("{:?}", err),
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
}
|
2022-08-21 23:36:07 +01:00
|
|
|
|
|
|
|
if let Err(err) = sway.poll() {
|
|
|
|
error!("{:?}", err);
|
|
|
|
}
|
2022-08-14 20:40:11 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
{
|
|
|
|
rx.attach(None, move |node| {
|
2022-08-15 21:11:17 +01:00
|
|
|
let value = node.name.as_deref().unwrap_or_else(|| node.get_id());
|
2022-08-14 20:40:11 +01:00
|
|
|
|
|
|
|
let pixbuf = icon::get_icon(&icon_theme, node.get_id(), self.icon_size);
|
|
|
|
|
|
|
|
if self.show_icon {
|
|
|
|
icon.set_pixbuf(pixbuf.as_ref());
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.show_title {
|
|
|
|
label.set_label(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
Continue(true)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-08-21 23:36:07 +01:00
|
|
|
Ok(container)
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
}
|