Skip to content

Commit

Permalink
screen notification popups
Browse files Browse the repository at this point in the history
  • Loading branch information
galister committed Sep 26, 2024
1 parent a077f2d commit bdbdbea
Show file tree
Hide file tree
Showing 4 changed files with 406 additions and 15 deletions.
3 changes: 3 additions & 0 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ pub mod common;
pub mod input;
pub mod notifications;

#[allow(clippy::all)]
mod notifications_dbus;

#[cfg(feature = "openvr")]
pub mod openvr;

Expand Down
62 changes: 61 additions & 1 deletion src/backend/notifications.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use dbus::{blocking::Connection, channel::MatchingReceiver, message::MatchRule};
use dbus::{
arg::{PropMap, Variant},
blocking::Connection,
channel::MatchingReceiver,
message::MatchRule,
};
use serde::Deserialize;
use std::{
sync::{
Expand All @@ -9,6 +14,7 @@ use std::{
};

use crate::{
backend::notifications_dbus::OrgFreedesktopNotifications,
overlays::toast::{Toast, ToastTopic},
state::AppState,
};
Expand Down Expand Up @@ -196,6 +202,60 @@ impl Drop for NotificationManager {
}
}

pub struct DbusNotificationSender {
connection: Connection,
}

impl DbusNotificationSender {
pub fn new() -> anyhow::Result<Self> {
Ok(Self {
connection: Connection::new_session()?,
})
}

pub fn notify_send(
&self,
summary: &str,
body: &str,
urgency: u8,
timeout: i32,
replaces_id: u32,
transient: bool,
) -> anyhow::Result<u32> {
let proxy = self.connection.with_proxy(
"org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
Duration::from_millis(1000),
);

let mut hints = PropMap::new();
hints.insert("urgency".to_string(), Variant(Box::new(urgency)));
hints.insert("transient".to_string(), Variant(Box::new(transient)));

Ok(proxy.notify(
"WlxOverlay-S",
replaces_id,
"",
summary,
body,
vec![],
hints,
timeout,
)?)
}

pub fn notify_close(&self, id: u32) -> anyhow::Result<()> {
let proxy = self.connection.with_proxy(
"org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
Duration::from_millis(1000),
);

proxy.close_notification(id)?;
Ok(())
}
}

fn parse_dbus(msg: &dbus::Message) -> anyhow::Result<Toast> {
let mut args = msg.iter_init();
let app_name: String = args.read()?;
Expand Down
267 changes: 267 additions & 0 deletions src/backend/notifications_dbus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
// This code was autogenerated with `dbus-codegen-rust -g -m None -d org.freedesktop.Notifications -p /org/freedesktop/Notifications`, see https://github.com/diwic/dbus-rs
use dbus as dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;

pub trait OrgFreedesktopDBusProperties {
fn get<R0: for<'b> arg::Get<'b> + 'static>(&self, interface_name: &str, property_name: &str) -> Result<R0, dbus::Error>;
fn get_all(&self, interface_name: &str) -> Result<arg::PropMap, dbus::Error>;
fn set<I2: arg::Arg + arg::Append>(&self, interface_name: &str, property_name: &str, value: I2) -> Result<(), dbus::Error>;
}

#[derive(Debug)]
pub struct OrgFreedesktopDBusPropertiesPropertiesChanged {
pub interface_name: String,
pub changed_properties: arg::PropMap,
pub invalidated_properties: Vec<String>,
}

impl arg::AppendAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.interface_name, i);
arg::RefArg::append(&self.changed_properties, i);
arg::RefArg::append(&self.invalidated_properties, i);
}
}

impl arg::ReadAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgFreedesktopDBusPropertiesPropertiesChanged {
interface_name: i.read()?,
changed_properties: i.read()?,
invalidated_properties: i.read()?,
})
}
}

impl dbus::message::SignalArgs for OrgFreedesktopDBusPropertiesPropertiesChanged {
const NAME: &'static str = "PropertiesChanged";
const INTERFACE: &'static str = "org.freedesktop.DBus.Properties";
}

impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopDBusProperties for blocking::Proxy<'a, C> {

fn get<R0: for<'b> arg::Get<'b> + 'static>(&self, interface_name: &str, property_name: &str) -> Result<R0, dbus::Error> {
self.method_call("org.freedesktop.DBus.Properties", "Get", (interface_name, property_name, ))
.and_then(|r: (arg::Variant<R0>, )| Ok((r.0).0, ))
}

fn get_all(&self, interface_name: &str) -> Result<arg::PropMap, dbus::Error> {
self.method_call("org.freedesktop.DBus.Properties", "GetAll", (interface_name, ))
.and_then(|r: (arg::PropMap, )| Ok(r.0, ))
}

fn set<I2: arg::Arg + arg::Append>(&self, interface_name: &str, property_name: &str, value: I2) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.DBus.Properties", "Set", (interface_name, property_name, arg::Variant(value), ))
}
}

pub trait OrgFreedesktopDBusIntrospectable {
fn introspect(&self) -> Result<String, dbus::Error>;
}

impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopDBusIntrospectable for blocking::Proxy<'a, C> {

fn introspect(&self) -> Result<String, dbus::Error> {
self.method_call("org.freedesktop.DBus.Introspectable", "Introspect", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
}

pub trait OrgFreedesktopDBusPeer {
fn ping(&self) -> Result<(), dbus::Error>;
fn get_machine_id(&self) -> Result<String, dbus::Error>;
}

impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopDBusPeer for blocking::Proxy<'a, C> {

fn ping(&self) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.DBus.Peer", "Ping", ())
}

fn get_machine_id(&self) -> Result<String, dbus::Error> {
self.method_call("org.freedesktop.DBus.Peer", "GetMachineId", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
}

pub trait OrgFreedesktopNotifications {
fn set_noti_window_visibility(&self, value: bool) -> Result<(), dbus::Error>;
fn toggle_dnd(&self) -> Result<bool, dbus::Error>;
fn set_dnd(&self, state: bool) -> Result<(), dbus::Error>;
fn get_dnd(&self) -> Result<bool, dbus::Error>;
fn manually_close_notification(&self, id: u32, timeout: bool) -> Result<(), dbus::Error>;
fn close_all_notifications(&self) -> Result<(), dbus::Error>;
fn hide_latest_notification(&self, close: bool) -> Result<(), dbus::Error>;
fn get_capabilities(&self) -> Result<Vec<String>, dbus::Error>;
fn notify(&self, app_name: &str, replaces_id: u32, app_icon: &str, summary: &str, body: &str, actions: Vec<&str>, hints: arg::PropMap, expire_timeout: i32) -> Result<u32, dbus::Error>;
fn close_notification(&self, id: u32) -> Result<(), dbus::Error>;
fn get_server_information(&self) -> Result<(String, String, String, String), dbus::Error>;
fn dnd(&self) -> Result<bool, dbus::Error>;
fn set_dnd_(&self, value: bool) -> Result<(), dbus::Error>;
}

#[derive(Debug)]
pub struct OrgFreedesktopNotificationsOnDndToggle {
pub dnd: bool,
}

impl arg::AppendAll for OrgFreedesktopNotificationsOnDndToggle {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.dnd, i);
}
}

impl arg::ReadAll for OrgFreedesktopNotificationsOnDndToggle {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgFreedesktopNotificationsOnDndToggle {
dnd: i.read()?,
})
}
}

impl dbus::message::SignalArgs for OrgFreedesktopNotificationsOnDndToggle {
const NAME: &'static str = "OnDndToggle";
const INTERFACE: &'static str = "org.freedesktop.Notifications";
}

#[derive(Debug)]
pub struct OrgFreedesktopNotificationsNotificationClosed {
pub id: u32,
pub reason: u32,
}

impl arg::AppendAll for OrgFreedesktopNotificationsNotificationClosed {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.id, i);
arg::RefArg::append(&self.reason, i);
}
}

impl arg::ReadAll for OrgFreedesktopNotificationsNotificationClosed {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgFreedesktopNotificationsNotificationClosed {
id: i.read()?,
reason: i.read()?,
})
}
}

impl dbus::message::SignalArgs for OrgFreedesktopNotificationsNotificationClosed {
const NAME: &'static str = "NotificationClosed";
const INTERFACE: &'static str = "org.freedesktop.Notifications";
}

#[derive(Debug)]
pub struct OrgFreedesktopNotificationsActionInvoked {
pub id: u32,
pub action_key: String,
}

impl arg::AppendAll for OrgFreedesktopNotificationsActionInvoked {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.id, i);
arg::RefArg::append(&self.action_key, i);
}
}

impl arg::ReadAll for OrgFreedesktopNotificationsActionInvoked {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgFreedesktopNotificationsActionInvoked {
id: i.read()?,
action_key: i.read()?,
})
}
}

impl dbus::message::SignalArgs for OrgFreedesktopNotificationsActionInvoked {
const NAME: &'static str = "ActionInvoked";
const INTERFACE: &'static str = "org.freedesktop.Notifications";
}

#[derive(Debug)]
pub struct OrgFreedesktopNotificationsNotificationReplied {
pub id: u32,
pub text: String,
}

impl arg::AppendAll for OrgFreedesktopNotificationsNotificationReplied {
fn append(&self, i: &mut arg::IterAppend) {
arg::RefArg::append(&self.id, i);
arg::RefArg::append(&self.text, i);
}
}

impl arg::ReadAll for OrgFreedesktopNotificationsNotificationReplied {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgFreedesktopNotificationsNotificationReplied {
id: i.read()?,
text: i.read()?,
})
}
}

impl dbus::message::SignalArgs for OrgFreedesktopNotificationsNotificationReplied {
const NAME: &'static str = "NotificationReplied";
const INTERFACE: &'static str = "org.freedesktop.Notifications";
}

impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgFreedesktopNotifications for blocking::Proxy<'a, C> {

fn set_noti_window_visibility(&self, value: bool) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "SetNotiWindowVisibility", (value, ))
}

fn toggle_dnd(&self) -> Result<bool, dbus::Error> {
self.method_call("org.freedesktop.Notifications", "ToggleDnd", ())
.and_then(|r: (bool, )| Ok(r.0, ))
}

fn set_dnd(&self, state: bool) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "SetDnd", (state, ))
}

fn get_dnd(&self) -> Result<bool, dbus::Error> {
self.method_call("org.freedesktop.Notifications", "GetDnd", ())
.and_then(|r: (bool, )| Ok(r.0, ))
}

fn manually_close_notification(&self, id: u32, timeout: bool) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "ManuallyCloseNotification", (id, timeout, ))
}

fn close_all_notifications(&self) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "CloseAllNotifications", ())
}

fn hide_latest_notification(&self, close: bool) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "HideLatestNotification", (close, ))
}

fn get_capabilities(&self) -> Result<Vec<String>, dbus::Error> {
self.method_call("org.freedesktop.Notifications", "GetCapabilities", ())
.and_then(|r: (Vec<String>, )| Ok(r.0, ))
}

fn notify(&self, app_name: &str, replaces_id: u32, app_icon: &str, summary: &str, body: &str, actions: Vec<&str>, hints: arg::PropMap, expire_timeout: i32) -> Result<u32, dbus::Error> {
self.method_call("org.freedesktop.Notifications", "Notify", (app_name, replaces_id, app_icon, summary, body, actions, hints, expire_timeout, ))
.and_then(|r: (u32, )| Ok(r.0, ))
}

fn close_notification(&self, id: u32) -> Result<(), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "CloseNotification", (id, ))
}

fn get_server_information(&self) -> Result<(String, String, String, String), dbus::Error> {
self.method_call("org.freedesktop.Notifications", "GetServerInformation", ())
}

fn dnd(&self) -> Result<bool, dbus::Error> {
<Self as blocking::stdintf::org_freedesktop_dbus::Properties>::get(self, "org.freedesktop.Notifications", "Dnd")
}

fn set_dnd_(&self, value: bool) -> Result<(), dbus::Error> {
<Self as blocking::stdintf::org_freedesktop_dbus::Properties>::set(self, "org.freedesktop.Notifications", "Dnd", value)
}
}
Loading

0 comments on commit bdbdbea

Please sign in to comment.