1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-01 18:51:04 +02:00

feat: common module options (show_if, on_click, tooltip)

The first three of many options that are common to all modules.

Resolves #36. Resolves partially #34.
This commit is contained in:
Jake Stanger 2022-11-28 21:55:08 +00:00
parent a3f90adaf1
commit c9e66d4664
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
15 changed files with 600 additions and 125 deletions

View file

@ -1,3 +1,4 @@
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup;
use chrono::{DateTime, Local};
@ -18,7 +19,10 @@ pub struct ClockModule {
/// Detail on available tokens can be found here:
/// <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>
#[serde(default = "default_format")]
pub(crate) format: String,
format: String,
#[serde(flatten)]
pub common: CommonConfig,
}
fn default_format() -> String {

View file

@ -1,7 +1,8 @@
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::{ButtonGeometry, Popup};
use crate::script::exec_command;
use crate::config::CommonConfig;
use color_eyre::{Report, Result};
use crate::script::Script;
use gtk::prelude::*;
use gtk::{Button, Label, Orientation};
use serde::Deserialize;
@ -17,6 +18,9 @@ pub struct CustomModule {
bar: Vec<Widget>,
/// Widgets to add to the popup container
popup: Option<Vec<Widget>>,
#[serde(flatten)]
pub common: CommonConfig,
}
/// Attempts to parse an `Orientation` from `String`
@ -164,8 +168,11 @@ impl Module<gtk::Box> for CustomModule {
spawn(async move {
while let Some(event) = rx.recv().await {
if event.cmd.starts_with('!') {
debug!("executing command: '{}'", &event.cmd[1..]);
if let Err(err) = exec_command(&event.cmd[1..]) {
let script = Script::from(&event.cmd[1..]);
debug!("executing command: '{}'", script.cmd);
// TODO: Migrate to use script.run
if let Err(err) = script.get_output().await {
error!("{err:?}");
}
} else if event.cmd == "popup:toggle" {

View file

@ -1,4 +1,5 @@
use crate::clients::wayland::{self, ToplevelChange};
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::{await_sync, icon};
use color_eyre::Result;
@ -23,6 +24,9 @@ pub struct FocusedModule {
icon_size: i32,
/// GTK icon theme to use.
icon_theme: Option<String>,
#[serde(flatten)]
pub common: CommonConfig,
}
const fn default_icon_size() -> i32 {

View file

@ -4,6 +4,7 @@ mod open_state;
use self::item::{Item, ItemButton, Window};
use self::open_state::OpenState;
use crate::clients::wayland::{self, ToplevelChange};
use crate::config::CommonConfig;
use crate::icon::find_desktop_file;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use color_eyre::{Help, Report};
@ -33,6 +34,9 @@ pub struct LauncherModule {
/// Name of the GTK icon theme to use.
icon_theme: Option<String>,
#[serde(flatten)]
pub common: CommonConfig,
}
#[derive(Debug, Clone)]

View file

@ -1,4 +1,5 @@
use crate::clients::mpd::{get_client, get_duration, get_elapsed, MpdConnectionError};
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup;
use color_eyre::Result;
@ -65,6 +66,9 @@ pub struct MpdModule {
/// Path to root of music directory.
#[serde(default = "default_music_dir")]
music_dir: PathBuf,
#[serde(flatten)]
pub common: CommonConfig,
}
fn default_socket() -> String {

View file

@ -1,39 +1,32 @@
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::script::exec_command;
use crate::script::{OutputStream, Script, ScriptMode};
use color_eyre::{Help, Report, Result};
use gtk::prelude::*;
use gtk::Label;
use serde::Deserialize;
use std::process::Stdio;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::process::Command;
use tokio::spawn;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::time::sleep;
use tokio::{select, spawn};
use tracing::error;
#[derive(Debug, Deserialize, Clone, Copy)]
#[serde(rename_all = "kebab-case")]
enum Mode {
Poll,
Watch,
}
#[derive(Debug, Deserialize, Clone)]
pub struct ScriptModule {
/// Path to script to execute.
path: String,
/// Script execution mode
#[serde(default = "default_mode")]
mode: Mode,
mode: ScriptMode,
/// Time in milliseconds between executions.
#[serde(default = "default_interval")]
interval: u64,
#[serde(flatten)]
pub common: CommonConfig,
}
/// `Mode::Poll`
const fn default_mode() -> Mode {
Mode::Poll
const fn default_mode() -> ScriptMode {
ScriptMode::Poll
}
/// 5000ms
@ -41,6 +34,16 @@ const fn default_interval() -> u64 {
5000
}
impl From<&ScriptModule> for Script {
fn from(module: &ScriptModule) -> Self {
Self {
mode: module.mode,
cmd: module.path.clone(),
interval: module.interval,
}
}
}
impl Module<Label> for ScriptModule {
type SendMessage = String;
type ReceiveMessage = ();
@ -51,78 +54,22 @@ impl Module<Label> for ScriptModule {
tx: Sender<ModuleUpdateEvent<Self::SendMessage>>,
_rx: Receiver<Self::ReceiveMessage>,
) -> Result<()> {
let interval = self.interval;
let path = self.path.clone();
let script: Script = self.into();
match self.mode {
Mode::Poll => spawn(async move {
loop {
match exec_command(&path) {
Ok(stdout) => tx
.send(ModuleUpdateEvent::Update(stdout))
.await
.expect("Failed to send stdout"),
Err(err) => error!("{:?}", err),
}
sleep(tokio::time::Duration::from_millis(interval)).await;
}
}),
Mode::Watch => spawn(async move {
loop {
let mut handle = Command::new("sh")
.args(["-c", &path])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.spawn()
.expect("Failed to spawn process");
let mut stdout_lines = BufReader::new(
handle
.stdout
.take()
.expect("Failed to take script handle stdout"),
)
.lines();
let mut stderr_lines = BufReader::new(
handle
.stderr
.take()
.expect("Failed to take script handle stderr"),
)
.lines();
loop {
select! {
_ = handle.wait() => break,
Ok(Some(line)) = stdout_lines.next_line() => {
tx.send(ModuleUpdateEvent::Update(line.to_string()))
.await
.expect("Failed to send stdout");
}
Ok(Some(line)) = stderr_lines.next_line() => {
error!("{:?}", Report::msg(line)
spawn(async move {
script.run(move |(out, _)| match out {
OutputStream::Stdout(stdout) => {
tx.try_send(ModuleUpdateEvent::Update(stdout))
.expect("Failed to send stdout"); }
OutputStream::Stderr(stderr) => {
error!("{:?}", Report::msg(stderr)
.wrap_err("Watched script error:")
.suggestion("Check the path to your script")
.suggestion("Check the script for errors")
.suggestion("If you expect the script to write to stderr, consider redirecting its output to /dev/null to suppress these messages")
)
}
}
}
while let Ok(Some(line)) = stdout_lines.next_line().await {
tx.send(ModuleUpdateEvent::Update(line.to_string()))
.await
.expect("Failed to send stdout");
}
sleep(tokio::time::Duration::from_millis(interval)).await;
}
}),
};
.suggestion("If you expect the script to write to stderr, consider redirecting its output to /dev/null to suppress these messages"));
}
}).await;
});
Ok(())
}

View file

@ -1,3 +1,4 @@
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use color_eyre::Result;
use gtk::prelude::*;
@ -19,6 +20,9 @@ pub struct SysInfoModule {
/// Number of seconds between refresh
#[serde(default = "Interval::default")]
interval: Interval,
#[serde(flatten)]
pub common: CommonConfig,
}
#[derive(Debug, Deserialize, Copy, Clone)]

View file

@ -1,5 +1,6 @@
use crate::await_sync;
use crate::clients::system_tray::get_tray_event_client;
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use color_eyre::Result;
use gtk::prelude::*;
@ -14,7 +15,10 @@ use tokio::sync::mpsc;
use tokio::sync::mpsc::{Receiver, Sender};
#[derive(Debug, Deserialize, Clone)]
pub struct TrayModule;
pub struct TrayModule {
#[serde(flatten)]
pub common: CommonConfig,
}
/// Gets a GTK `Image` component
/// for the status notifier item's icon.

View file

@ -1,5 +1,6 @@
use crate::await_sync;
use crate::clients::sway::{get_client, get_sub_client};
use crate::config::CommonConfig;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use color_eyre::{Report, Result};
use gtk::prelude::*;
@ -19,6 +20,9 @@ pub struct WorkspacesModule {
/// Whether to display buttons for all monitors.
#[serde(default = "crate::config::default_false")]
all_monitors: bool,
#[serde(flatten)]
pub common: CommonConfig,
}
#[derive(Clone, Debug)]