This commit is contained in:
end-4
2024-02-22 15:35:06 +07:00
commit 8db26e9707
4220 changed files with 208544 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
- This folder is for programs that have a proper folder structure that should be compiled then copied to .config/eww/scripts, if you wish.
- If you don't mind using prebuilt binaries, you can ignore this folder
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "notify-receive"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.69"
chrono = "0.4.23"
gtk = "0.17.1"
mpsc = "0.1.0"
nohash-hasher = "0.2.0"
serde = {version = "1.0.152", features = ["derive"]}
serde_json = "1.0.93"
tokio = { version = "1.26.0", features = ["rt-multi-thread", "macros", "sync", "time"] }
unix-named-pipe = "0.2.0"
zbus = "3.10.0"
+144
View File
@@ -0,0 +1,144 @@
use super::NotificationArc;
use chrono::Local;
use std::process::Command;
use std::path::Path;
use gtk::{prelude::IconThemeExt, IconLookupFlags, IconTheme};
use std::collections::HashMap;
use zbus::zvariant::Value;
use zbus::{dbus_interface, Connection};
use crate::Notification;
const CAPABILITIES: [&str; 6] = [
"icons",
"actions",
"body",
"body-images",
"action-icons",
"persistence",
];
const SERVER_INFORMATION: (&str, &str, &str, &str) =
("notify-receive", "neoney.dev", "0.0.1", "1.0");
const NAME: &str = "org.freedesktop.Notifications";
const PATH: &str = "/org/freedesktop/Notifications";
struct NotificationServer {
notifications: NotificationArc,
biggest_id: u32,
}
impl NotificationServer {
fn new(notifications: NotificationArc) -> Self {
NotificationServer {
notifications,
biggest_id: 0,
}
}
}
#[dbus_interface(name = "org.freedesktop.Notifications")]
impl NotificationServer {
async fn notify(
&mut self,
app_name: String,
replaces_id: u32,
app_icon: String,
summary: String,
body: String,
actions: Vec<String>,
hints: HashMap<String, Value<'_>>,
expire_timeout: i32,
) -> u32 {
gtk::init().expect("Failed to initialize GTK");
let dt = Local::now();
let time = dt.time().format("%H:%M").to_string();
let changed_id = if replaces_id != 0 {
replaces_id
} else {
self.biggest_id += 1;
self.biggest_id
};
let icon = match app_icon.as_str() {
"" => "".to_string(),
app_icon => {
let icon_theme = IconTheme::default().expect("Failed to find icon theme.");
let icon = icon_theme.lookup_icon(app_icon, 256, IconLookupFlags::empty());
icon.map_or(app_icon.to_string(), |icon| {
icon.filename().unwrap().to_string_lossy().to_string()
})
}
};
let payload = Notification {
id: changed_id,
app_name,
summary,
time,
body,
actions,
urgency: hints
.get("urgency")
.and_then(|v| v.clone().downcast())
.unwrap_or_default(),
icon,
timeout: expire_timeout,
visible: true,
};
let mut notifs = self.notifications.lock().await;
notifs.insert(changed_id, payload);
let path = Path::new("./scripts/notification-on-receive.sh");
if path.exists() {
Command::new(path)
.spawn()
.expect("Failed to execute command");
}
println!(
"{}",
serde_json::to_string(&notifs.values().collect::<Vec<_>>()).unwrap()
);
changed_id
}
async fn close(&mut self, id: u32) {
let mut notifs = self.notifications.lock().await;
if let Some(notif) = notifs.get_mut(&id) {
notif.visible = false;
};
println!(
"{}",
serde_json::to_string(&notifs.values().collect::<Vec<_>>()).unwrap()
);
}
fn get_capabilities(&self) -> &[&str] {
&CAPABILITIES
}
fn get_server_information(&self) -> (&str, &str, &str, &str) {
SERVER_INFORMATION
}
}
pub async fn async_run(notifications: NotificationArc) -> zbus::Result<()> {
let connection = Connection::session().await?;
let server = NotificationServer::new(notifications);
connection.object_server().at(PATH, server).await?;
connection.request_name(NAME).await?;
loop {
std::future::pending::<()>().await;
}
}
+89
View File
@@ -0,0 +1,89 @@
mod dbus;
use std::fs;
use std::time::Duration;
use std::{collections::HashMap, hash::BuildHasherDefault, path::Path, sync::Arc};
use std::io::Read;
use tokio::sync::Mutex;
use anyhow::Result;
use nohash_hasher::NoHashHasher;
use zbus::export::serde::Serialize;
use crate::dbus::async_run;
type NotificationArc =
Arc<Mutex<HashMap<u32, Notification, BuildHasherDefault<NoHashHasher<u32>>>>>;
#[derive(Serialize)]
pub struct Notifications<'a> {
pub notifications: Vec<&'a Notification>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Notification {
pub id: u32,
pub app_name: String,
pub summary: String,
pub body: String,
pub time: String,
pub icon: String,
pub timeout: i32,
pub urgency: u8,
pub actions: Vec<String>,
pub visible: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Action {
Close,
Clear,
Notify(Notification),
}
#[tokio::main]
async fn main() -> Result<()> {
let notifications: NotificationArc = Arc::new(Mutex::new(HashMap::with_hasher(
BuildHasherDefault::default(),
)));
fs::remove_file(Path::new("/var/run/user/1000/notify-receive.pipe")).ok();
unix_named_pipe::create("/var/run/user/1000/notify-receive.pipe", Some(0o644))?;
let mut reader = unix_named_pipe::open_read("/var/run/user/1000/notify-receive.pipe")?;
let pipe_notifications = notifications.clone();
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_millis(100));
loop {
let mut contents = String::new();
if reader.read_to_string(&mut contents).is_ok() && !contents.is_empty() {
let mut notifs = pipe_notifications.lock().await;
for line in contents.lines() {
if line.is_empty() {
continue;
}
if let Ok(id) = line.parse::<u32>() {
if let Some(notif) = notifs.get_mut(&id) {
notif.visible = false;
}
}
}
println!(
"{}",
serde_json::to_string(&notifs.values().collect::<Vec<_>>()).unwrap()
);
}
interval.tick().await;
}
});
async_run(notifications.clone()).await?;
Ok(())
}