2023-04-29 22:08:02 +01:00
|
|
|
use crate::clients::wayland::{self, ToplevelEvent};
|
2023-01-28 23:01:44 +00:00
|
|
|
use crate::config::{CommonConfig, TruncateMode};
|
2023-07-16 18:57:00 +01:00
|
|
|
use crate::gtk_helpers::IronbarGtkExt;
|
2023-01-29 17:46:02 +00:00
|
|
|
use crate::image::ImageProvider;
|
2023-07-16 18:57:00 +01:00
|
|
|
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
2024-03-14 22:35:33 +00:00
|
|
|
use crate::{glib_recv, module_impl, send_async, spawn, try_send};
|
2022-08-21 23:36:07 +01:00
|
|
|
use color_eyre::Result;
|
2022-08-14 20:40:11 +01:00
|
|
|
use gtk::prelude::*;
|
2023-01-29 18:38:57 +00:00
|
|
|
use gtk::Label;
|
2022-08-14 20:40:11 +01:00
|
|
|
use serde::Deserialize;
|
2024-01-07 23:50:10 +00:00
|
|
|
use tokio::sync::mpsc;
|
2023-05-20 14:36:04 +01:00
|
|
|
use tracing::debug;
|
2022-08-14 20:40:11 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
2024-05-10 22:40:00 +01:00
|
|
|
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
|
2022-08-14 20:40:11 +01:00
|
|
|
pub struct FocusedModule {
|
2022-08-28 16:57:41 +01:00
|
|
|
/// Whether to show icon on the bar.
|
2024-05-19 15:16:01 +01:00
|
|
|
///
|
|
|
|
/// **Default**: `true`
|
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.
|
2024-05-19 15:16:01 +01:00
|
|
|
///
|
|
|
|
/// **Default**: `true`
|
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.
|
2024-05-19 15:16:01 +01:00
|
|
|
///
|
|
|
|
/// **Default**: `32`
|
2022-08-14 20:40:11 +01:00
|
|
|
#[serde(default = "default_icon_size")]
|
|
|
|
icon_size: i32,
|
2022-11-28 21:55:08 +00:00
|
|
|
|
2024-05-19 15:16:01 +01:00
|
|
|
// -- common --
|
|
|
|
/// See [truncate options](module-level-options#truncate-mode).
|
|
|
|
///
|
|
|
|
/// **Default**: `null`
|
2023-01-28 23:01:44 +00:00
|
|
|
truncate: Option<TruncateMode>,
|
|
|
|
|
2024-05-19 15:16:01 +01:00
|
|
|
/// See [common options](module-level-options#common-options).
|
2022-11-28 21:55:08 +00:00
|
|
|
#[serde(flatten)]
|
2022-12-04 23:23:22 +00:00
|
|
|
pub common: Option<CommonConfig>,
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
|
2023-07-03 22:47:36 +01:00
|
|
|
impl Default for FocusedModule {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
show_icon: crate::config::default_true(),
|
|
|
|
show_title: crate::config::default_true(),
|
|
|
|
icon_size: default_icon_size(),
|
|
|
|
truncate: None,
|
|
|
|
common: Some(CommonConfig::default()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-14 20:40:11 +01:00
|
|
|
const fn default_icon_size() -> i32 {
|
|
|
|
32
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Module<gtk::Box> for FocusedModule {
|
2023-10-19 20:21:27 +01:00
|
|
|
type SendMessage = Option<(String, String)>;
|
2022-09-25 22:49:00 +01:00
|
|
|
type ReceiveMessage = ();
|
|
|
|
|
2024-03-14 22:35:33 +00:00
|
|
|
module_impl!("focused");
|
2022-12-04 23:23:22 +00:00
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
fn spawn_controller(
|
|
|
|
&self,
|
|
|
|
_info: &ModuleInfo,
|
2024-01-07 23:42:34 +00:00
|
|
|
context: &WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
|
2024-01-07 23:50:10 +00:00
|
|
|
_rx: mpsc::Receiver<Self::ReceiveMessage>,
|
2022-09-25 22:49:00 +01:00
|
|
|
) -> Result<()> {
|
2024-01-07 23:42:34 +00:00
|
|
|
let tx = context.tx.clone();
|
2024-01-07 23:50:10 +00:00
|
|
|
let wl = context.client::<wayland::Client>();
|
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
spawn(async move {
|
2024-04-24 21:29:44 +01:00
|
|
|
let mut current = None;
|
|
|
|
|
2024-01-07 23:50:10 +00:00
|
|
|
let mut wlrx = wl.subscribe_toplevels();
|
|
|
|
let handles = wl.toplevel_info_all();
|
2022-08-25 21:53:42 +01:00
|
|
|
|
2024-01-07 23:50:10 +00:00
|
|
|
let focused = handles.into_iter().find(|info| info.focused);
|
2023-04-29 22:08:02 +01:00
|
|
|
|
|
|
|
if let Some(focused) = focused {
|
2024-04-24 21:29:44 +01:00
|
|
|
current = Some(focused.id);
|
|
|
|
|
2023-04-29 22:08:02 +01:00
|
|
|
try_send!(
|
|
|
|
tx,
|
2023-10-19 20:21:27 +01:00
|
|
|
ModuleUpdateEvent::Update(Some((focused.title.clone(), focused.app_id)))
|
2023-04-29 22:08:02 +01:00
|
|
|
);
|
|
|
|
};
|
2022-08-25 21:53:42 +01:00
|
|
|
|
2023-04-29 22:08:02 +01:00
|
|
|
while let Ok(event) = wlrx.recv().await {
|
2023-10-19 20:21:27 +01:00
|
|
|
match event {
|
2024-01-07 23:50:10 +00:00
|
|
|
ToplevelEvent::Update(info) => {
|
2023-10-19 20:21:27 +01:00
|
|
|
if info.focused {
|
|
|
|
debug!("Changing focus");
|
2024-04-24 21:29:44 +01:00
|
|
|
|
|
|
|
current = Some(info.id);
|
|
|
|
|
2023-10-19 20:21:27 +01:00
|
|
|
send_async!(
|
|
|
|
tx,
|
|
|
|
ModuleUpdateEvent::Update(Some((
|
|
|
|
info.title.clone(),
|
|
|
|
info.app_id.clone()
|
|
|
|
)))
|
|
|
|
);
|
2024-04-24 21:29:44 +01:00
|
|
|
} else if info.id == current.unwrap_or_default() {
|
|
|
|
debug!("Clearing focus");
|
|
|
|
current = None;
|
2023-10-19 22:43:02 +01:00
|
|
|
send_async!(tx, ModuleUpdateEvent::Update(None));
|
2023-10-19 20:21:27 +01:00
|
|
|
}
|
2023-04-29 22:08:02 +01:00
|
|
|
}
|
2024-01-07 23:50:10 +00:00
|
|
|
ToplevelEvent::Remove(info) => {
|
2023-10-19 20:21:27 +01:00
|
|
|
if info.focused {
|
|
|
|
debug!("Clearing focus");
|
2024-04-24 21:29:44 +01:00
|
|
|
current = None;
|
2023-10-19 20:21:27 +01:00
|
|
|
send_async!(tx, ModuleUpdateEvent::Update(None));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ToplevelEvent::New(_) => {}
|
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>,
|
2022-10-15 16:27:25 +01:00
|
|
|
info: &ModuleInfo,
|
2023-07-16 18:57:00 +01:00
|
|
|
) -> Result<ModuleParts<gtk::Box>> {
|
2023-01-29 18:38:57 +00:00
|
|
|
let icon_theme = info.icon_theme;
|
2022-08-14 20:40:11 +01:00
|
|
|
|
2024-02-18 14:54:17 +00:00
|
|
|
let container = gtk::Box::new(info.bar_position.orientation(), 5);
|
2022-09-25 22:49:00 +01:00
|
|
|
|
2023-05-06 00:40:06 +01:00
|
|
|
let icon = gtk::Image::new();
|
2023-06-17 16:43:38 +01:00
|
|
|
if self.show_icon {
|
2023-07-16 18:57:00 +01:00
|
|
|
icon.add_class("icon");
|
2023-06-17 16:43:38 +01:00
|
|
|
container.add(&icon);
|
|
|
|
}
|
2023-05-06 00:40:06 +01:00
|
|
|
|
|
|
|
let label = Label::new(None);
|
2023-07-16 18:57:00 +01:00
|
|
|
label.add_class("label");
|
2022-09-25 22:49:00 +01:00
|
|
|
|
2023-01-28 23:01:44 +00:00
|
|
|
if let Some(truncate) = self.truncate {
|
|
|
|
truncate.truncate_label(&label);
|
|
|
|
}
|
|
|
|
|
2022-09-25 22:49:00 +01:00
|
|
|
container.add(&label);
|
|
|
|
|
|
|
|
{
|
2023-01-29 18:38:57 +00:00
|
|
|
let icon_theme = icon_theme.clone();
|
2023-12-17 23:51:43 +00:00
|
|
|
glib_recv!(context.subscribe(), data => {
|
2023-10-19 20:21:27 +01:00
|
|
|
if let Some((name, id)) = data {
|
|
|
|
if self.show_icon {
|
|
|
|
match ImageProvider::parse(&id, &icon_theme, true, self.icon_size)
|
|
|
|
.map(|image| image.load_into_image(icon.clone()))
|
|
|
|
{
|
|
|
|
Some(Ok(())) => icon.show(),
|
|
|
|
_ => icon.hide(),
|
|
|
|
}
|
2023-06-17 16:43:58 +01:00
|
|
|
}
|
2022-08-14 20:40:11 +01:00
|
|
|
|
2023-10-19 20:21:27 +01:00
|
|
|
if self.show_title {
|
|
|
|
label.show();
|
2024-06-02 17:42:18 +01:00
|
|
|
label.set_label(&name);
|
2023-10-19 20:21:27 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
icon.hide();
|
|
|
|
label.hide();
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-07-16 18:57:00 +01:00
|
|
|
Ok(ModuleParts {
|
2022-09-25 22:49:00 +01:00
|
|
|
widget: container,
|
|
|
|
popup: None,
|
|
|
|
})
|
2022-08-14 20:40:11 +01:00
|
|
|
}
|
|
|
|
}
|