2022-09-25 22:49:00 +01:00
|
|
|
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
|
|
|
|
use crate::sway::node::{get_node_id, get_open_windows};
|
|
|
|
use crate::sway::{get_client, get_sub_client};
|
|
|
|
use crate::{await_sync, icon};
|
2022-08-21 23:36:07 +01:00
|
|
|
use color_eyre::Result;
|
2022-08-14 20:40:11 +01:00
|
|
|
use glib::Continue;
|
|
|
|
use gtk::prelude::*;
|
|
|
|
use gtk::{IconTheme, Image, Label, Orientation};
|
|
|
|
use serde::Deserialize;
|
2022-09-25 22:49:00 +01:00
|
|
|
use swayipc_async::WindowChange;
|
|
|
|
use tokio::spawn;
|
|
|
|
use tokio::sync::mpsc::{Receiver, Sender};
|
|
|
|
use tracing::trace;
|
2022-08-14 20:40:11 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
|
|
pub struct FocusedModule {
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Whether to show icon on the bar.
|
2022-08-14 20:40:11 +01:00
|
|
|
#[serde(default = "crate::config::default_true")]
|
|
|
|
show_icon: bool,
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Whether to show app name on the bar.
|
2022-08-14 20:40:11 +01:00
|
|
|
#[serde(default = "crate::config::default_true")]
|
|
|
|
show_title: bool,
|
|
|
|
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Icon size in pixels.
|
2022-08-14 20:40:11 +01:00
|
|
|
#[serde(default = "default_icon_size")]
|
|
|
|
icon_size: i32,
|
2022-08-28 16:57:41 +01:00
|
|
|
/// GTK icon theme to use.
|
2022-08-14 20:40:11 +01:00
|
|
|
icon_theme: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
const fn default_icon_size() -> i32 {
|
|
|
|
32
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Module<gtk::Box> for FocusedModule {
|
2022-09-25 22:49:00 +01:00
|
|
|
type SendMessage = (String, String);
|
|
|
|
type ReceiveMessage = ();
|
|
|
|
|
|
|
|
fn spawn_controller(
|
|
|
|
&self,
|
|
|
|
_info: &ModuleInfo,
|
|
|
|
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
|
|
|
|
_rx: Receiver<Self::ReceiveMessage>,
|
|
|
|
) -> Result<()> {
|
|
|
|
let focused = await_sync(async {
|
|
|
|
let sway = get_client().await;
|
|
|
|
let mut sway = sway.lock().await;
|
|
|
|
get_open_windows(&mut sway)
|
|
|
|
.await
|
|
|
|
.expect("Failed to get open windows")
|
2022-08-25 21:53:42 +01:00
|
|
|
.into_iter()
|
|
|
|
.find(|node| node.focused)
|
2022-09-25 22:49:00 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(node) = focused {
|
|
|
|
let id = get_node_id(&node);
|
|
|
|
let name = node.name.as_deref().unwrap_or(id);
|
2022-08-14 20:40:11 +01:00
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
tx.try_send(ModuleUpdateEvent::Update((
|
|
|
|
name.to_string(),
|
|
|
|
id.to_string(),
|
|
|
|
)))?;
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
spawn(async move {
|
|
|
|
let mut srx = {
|
|
|
|
let sway = get_sub_client();
|
2022-08-25 21:53:42 +01:00
|
|
|
sway.subscribe_window()
|
|
|
|
};
|
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
trace!("Set up Sway window subscription");
|
|
|
|
|
|
|
|
while let Ok(payload) = srx.recv().await {
|
|
|
|
let update = match payload.change {
|
|
|
|
WindowChange::Focus => true,
|
|
|
|
WindowChange::Title => payload.container.focused,
|
2022-08-25 21:53:42 +01:00
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if update {
|
2022-09-25 22:49:00 +01:00
|
|
|
let node = payload.container;
|
|
|
|
|
|
|
|
let id = get_node_id(&node);
|
|
|
|
let name = node.name.as_deref().unwrap_or(id);
|
|
|
|
|
|
|
|
tx.try_send(ModuleUpdateEvent::Update((
|
|
|
|
name.to_string(),
|
|
|
|
id.to_string(),
|
|
|
|
)))
|
|
|
|
.expect("Failed to send focus update");
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_widget(
|
|
|
|
self,
|
|
|
|
context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
|
|
|
_info: &ModuleInfo,
|
|
|
|
) -> Result<ModuleWidget<gtk::Box>> {
|
|
|
|
let icon_theme = IconTheme::new();
|
|
|
|
|
|
|
|
if let Some(theme) = self.icon_theme {
|
|
|
|
icon_theme.set_custom_theme(Some(&theme));
|
|
|
|
}
|
2022-08-14 20:40:11 +01:00
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
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);
|
|
|
|
|
|
|
|
{
|
|
|
|
context.widget_rx.attach(None, move |(name, id)| {
|
|
|
|
let pixbuf = icon::get_icon(&icon_theme, &id, self.icon_size);
|
2022-08-14 20:40:11 +01:00
|
|
|
|
|
|
|
if self.show_icon {
|
|
|
|
icon.set_pixbuf(pixbuf.as_ref());
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.show_title {
|
2022-09-25 22:49:00 +01:00
|
|
|
label.set_label(&name);
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Continue(true)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
Ok(ModuleWidget {
|
|
|
|
widget: container,
|
|
|
|
popup: None,
|
|
|
|
})
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
}
|