use std::fmt::Debug; use std::rc::Rc; use std::sync::Arc; use color_eyre::Result; use glib::IsA; use gtk::gdk::{EventMask, Monitor}; use gtk::prelude::*; use gtk::{Application, Button, EventBox, IconTheme, Orientation, Revealer, Widget}; use tokio::sync::{broadcast, mpsc}; use tracing::debug; use crate::clients::{ClientResult, ProvidesClient, ProvidesFallibleClient}; use crate::config::{BarPosition, CommonConfig, TransitionType}; use crate::gtk_helpers::{IronbarGtkExt, WidgetGeometry}; use crate::popup::Popup; use crate::{glib_recv_mpsc, send, Ironbar}; #[cfg(feature = "clipboard")] pub mod clipboard; /// Displays the current date and time. /// /// A custom date/time format string can be set in the config. /// /// Clicking the widget opens a popup containing the current time /// with second-level precision and a calendar. #[cfg(feature = "clock")] pub mod clock; pub mod custom; #[cfg(feature = "focused")] pub mod focused; pub mod label; #[cfg(feature = "launcher")] pub mod launcher; #[cfg(feature = "music")] pub mod music; #[cfg(feature = "notifications")] pub mod notifications; pub mod script; #[cfg(feature = "sys_info")] pub mod sysinfo; #[cfg(feature = "tray")] pub mod tray; #[cfg(feature = "upower")] pub mod upower; #[cfg(feature = "volume")] pub mod volume; #[cfg(feature = "workspaces")] pub mod workspaces; #[derive(Clone)] pub enum ModuleLocation { Left, Center, Right, } #[derive(Clone)] pub struct ModuleInfo<'a> { pub app: &'a Application, pub location: ModuleLocation, pub bar_position: BarPosition, pub monitor: &'a Monitor, pub output_name: &'a str, pub icon_theme: &'a IconTheme, } #[derive(Debug, Clone)] pub enum ModuleUpdateEvent { /// Sends an update to the module UI. Update(T), /// Toggles the open state of the popup. /// Takes the button ID. TogglePopup(usize), /// Force sets the popup open. /// Takes the button ID. OpenPopup(usize), #[cfg(feature = "launcher")] OpenPopupAt(WidgetGeometry), /// Force sets the popup closed. ClosePopup, } pub struct WidgetContext where TSend: Clone, { pub id: usize, pub ironbar: Rc, pub popup: Rc, pub tx: mpsc::Sender>, pub update_tx: broadcast::Sender, pub controller_tx: mpsc::Sender, // TODO: Don't like this - need some serious refactoring to deal with it // This is a hack to be able to pass data from module -> popup creation // for custom widget only. pub button_id: usize, _update_rx: broadcast::Receiver, } impl WidgetContext where TSend: Clone, { /// Gets client `T` from the context. /// /// This is a shorthand to avoid needing to go through /// `context.ironbar.clients`. pub fn client(&self) -> Arc where WidgetContext: ProvidesClient, { ProvidesClient::provide(self) } pub fn try_client(&self) -> ClientResult where WidgetContext: ProvidesFallibleClient, { ProvidesFallibleClient::try_provide(self) } /// Subscribes to events sent from this widget. pub fn subscribe(&self) -> broadcast::Receiver { self.update_tx.subscribe() } } pub struct ModuleParts> { pub widget: W, pub popup: Option, } impl> ModuleParts { fn new(widget: W, popup: Option) -> Self { Self { widget, popup } } pub fn setup_identifiers(&self, common: &CommonConfig) { if let Some(ref name) = common.name { self.widget.set_widget_name(name); if let Some(ref popup) = self.popup { popup.container.set_widget_name(&format!("popup-{name}")); } } if let Some(ref class) = common.class { // gtk counts classes with spaces as the same class for part in class.split(' ') { self.widget.style_context().add_class(part); } if let Some(ref popup) = self.popup { for part in class.split(' ') { popup .container .style_context() .add_class(&format!("popup-{part}")); } } } } } #[derive(Debug, Clone)] pub struct ModulePopupParts { /// The popup container, with all its contents pub container: gtk::Box, /// An array of buttons which can be used for opening the popup. /// For most modules, this will only be a single button. /// For some advanced modules, such as `Launcher`, this is all item buttons. pub buttons: Vec