dbus refactor
This commit is contained in:
@@ -115,7 +115,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
|
|
||||||
let mut overlays = OverlayWindowManager::<OpenVrOverlayData>::new(&mut app, headless)?;
|
let mut overlays = OverlayWindowManager::<OpenVrOverlayData>::new(&mut app, headless)?;
|
||||||
let mut notifications = NotificationManager::new();
|
let mut notifications = NotificationManager::new();
|
||||||
notifications.run_dbus();
|
notifications.run_dbus(&mut app.dbus);
|
||||||
notifications.run_udp();
|
notifications.run_udp();
|
||||||
|
|
||||||
let mut playspace = playspace::PlayspaceMover::new();
|
let mut playspace = playspace::PlayspaceMover::new();
|
||||||
@@ -198,6 +198,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
next_device_update = Instant::now() + Duration::from_secs(30);
|
next_device_update = Instant::now() + Duration::from_secs(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.dbus.tick();
|
||||||
notifications.submit_pending(&mut app);
|
notifications.submit_pending(&mut app);
|
||||||
|
|
||||||
app.tasks.retrieve_due(&mut due_tasks);
|
app.tasks.retrieve_due(&mut due_tasks);
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
let mut lines = LinePool::new(&app)?;
|
let mut lines = LinePool::new(&app)?;
|
||||||
|
|
||||||
let mut notifications = NotificationManager::new();
|
let mut notifications = NotificationManager::new();
|
||||||
notifications.run_dbus();
|
notifications.run_dbus(&mut app.dbus);
|
||||||
notifications.run_udp();
|
notifications.run_udp();
|
||||||
|
|
||||||
let mut delete_queue = vec![];
|
let mut delete_queue = vec![];
|
||||||
@@ -480,6 +480,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
)?;
|
)?;
|
||||||
// End layer submit
|
// End layer submit
|
||||||
|
|
||||||
|
app.dbus.tick();
|
||||||
notifications.submit_pending(&mut app);
|
notifications.submit_pending(&mut app);
|
||||||
|
|
||||||
app.tasks.retrieve_due(&mut due_tasks);
|
app.tasks.retrieve_due(&mut due_tasks);
|
||||||
|
|||||||
@@ -37,11 +37,12 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use subsystem::notifications::DbusNotificationSender;
|
|
||||||
use sysinfo::Pid;
|
use sysinfo::Pid;
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
|
use crate::subsystem::dbus::DbusConnector;
|
||||||
|
|
||||||
pub static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
pub static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||||
pub static RUNNING: AtomicBool = AtomicBool::new(true);
|
pub static RUNNING: AtomicBool = AtomicBool::new(true);
|
||||||
|
|
||||||
@@ -168,8 +169,7 @@ fn auto_run(args: Args) {
|
|||||||
|
|
||||||
let instructions = format!("Could not connect to runtime.\n{instructions}");
|
let instructions = format!("Could not connect to runtime.\n{instructions}");
|
||||||
|
|
||||||
let _ = DbusNotificationSender::new()
|
let _ = DbusConnector::default().notify_send("WlxOverlay-S", &instructions, 1, 0, 0, false);
|
||||||
.and_then(|s| s.notify_send("WlxOverlay-S", &instructions, 1, 0, 0, false));
|
|
||||||
|
|
||||||
#[cfg(not(any(feature = "openvr", feature = "openxr")))]
|
#[cfg(not(any(feature = "openvr", feature = "openxr")))]
|
||||||
compile_error!("No VR support! Enable either openvr or openxr features!");
|
compile_error!("No VR support! Enable either openvr or openxr features!");
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use crate::{
|
|||||||
window::OverlayWindowConfig,
|
window::OverlayWindowConfig,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use dbus::message::MatchRule;
|
||||||
use glam::{Affine3A, Quat, Vec3, vec3};
|
use glam::{Affine3A, Quat, Vec3, vec3};
|
||||||
use slotmap::{SlotMap, new_key_type};
|
use slotmap::{SlotMap, new_key_type};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
@@ -64,6 +65,7 @@ pub fn create_keyboard(
|
|||||||
};
|
};
|
||||||
|
|
||||||
backend.active_keymap = backend.add_new_keymap(keymap.as_ref(), app)?;
|
backend.active_keymap = backend.add_new_keymap(keymap.as_ref(), app)?;
|
||||||
|
backend.watch_dbus(app);
|
||||||
|
|
||||||
Ok(OverlayWindowConfig {
|
Ok(OverlayWindowConfig {
|
||||||
name: KEYBOARD_NAME.into(),
|
name: KEYBOARD_NAME.into(),
|
||||||
@@ -112,6 +114,27 @@ impl KeyboardBackend {
|
|||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn watch_dbus(&mut self, app: &mut AppState) {
|
||||||
|
let rules = [
|
||||||
|
MatchRule::new()
|
||||||
|
.with_member("CurrentInputMethod")
|
||||||
|
.with_interface("org.fcitx.Fcitx.Controller1")
|
||||||
|
.with_path("/controller")
|
||||||
|
.with_sender("org.fcitx.Fcitx5"),
|
||||||
|
MatchRule::new_signal("org.kde.KeyboardLayouts", "layoutChanged").with_path("/Layouts"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for rule in rules {
|
||||||
|
let _ = app.dbus.add_match(
|
||||||
|
rule,
|
||||||
|
Box::new(move |(), _, msg| {
|
||||||
|
log::warn!("new keymap: {msg:?}");
|
||||||
|
true
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn switch_keymap(&mut self, keymap: &XkbKeymap, app: &mut AppState) -> anyhow::Result<()> {
|
fn switch_keymap(&mut self, keymap: &XkbKeymap, app: &mut AppState) -> anyhow::Result<()> {
|
||||||
let Some(layout_name) = keymap.inner.layouts().next() else {
|
let Some(layout_name) = keymap.inner.layouts().next() else {
|
||||||
log::error!("XKB keymap without a layout!");
|
log::error!("XKB keymap without a layout!");
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ impl ScreenBackend {
|
|||||||
pub fn new_pw(
|
pub fn new_pw(
|
||||||
output: &WlxOutput,
|
output: &WlxOutput,
|
||||||
token: Option<&str>,
|
token: Option<&str>,
|
||||||
app: &AppState,
|
app: &mut AppState,
|
||||||
) -> anyhow::Result<(Self, Option<String> /* pipewire restore token */)> {
|
) -> anyhow::Result<(Self, Option<String> /* pipewire restore token */)> {
|
||||||
let name = output.name.clone();
|
let name = output.name.clone();
|
||||||
let embed_mouse = !app.session.config.double_cursor_fix;
|
let embed_mouse = !app.session.config.double_cursor_fix;
|
||||||
|
|
||||||
let select_screen_result = select_pw_screen(
|
let select_screen_result = select_pw_screen(
|
||||||
|
app,
|
||||||
&format!(
|
&format!(
|
||||||
"Now select: {} {} {} @ {},{}",
|
"Now select: {} {} {} @ {},{}",
|
||||||
&output.name,
|
&output.name,
|
||||||
@@ -56,6 +57,7 @@ impl ScreenBackend {
|
|||||||
|
|
||||||
#[allow(clippy::fn_params_excessive_bools)]
|
#[allow(clippy::fn_params_excessive_bools)]
|
||||||
pub(super) fn select_pw_screen(
|
pub(super) fn select_pw_screen(
|
||||||
|
app: &mut AppState,
|
||||||
instructions: &str,
|
instructions: &str,
|
||||||
token: Option<&str>,
|
token: Option<&str>,
|
||||||
embed_mouse: bool,
|
embed_mouse: bool,
|
||||||
@@ -63,7 +65,6 @@ pub(super) fn select_pw_screen(
|
|||||||
persist: bool,
|
persist: bool,
|
||||||
multiple: bool,
|
multiple: bool,
|
||||||
) -> Result<PipewireSelectScreenResult, wlx_capture::pipewire::AshpdError> {
|
) -> Result<PipewireSelectScreenResult, wlx_capture::pipewire::AshpdError> {
|
||||||
use crate::subsystem::notifications::DbusNotificationSender;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wlx_capture::pipewire::pipewire_select_screen;
|
use wlx_capture::pipewire::pipewire_select_screen;
|
||||||
|
|
||||||
@@ -80,10 +81,8 @@ pub(super) fn select_pw_screen(
|
|||||||
task::Poll::Pending => {
|
task::Poll::Pending => {
|
||||||
if Instant::now() >= print_at {
|
if Instant::now() >= print_at {
|
||||||
log::info!("{instructions}");
|
log::info!("{instructions}");
|
||||||
if let Ok(sender) = DbusNotificationSender::new()
|
if let Ok(id) = app.dbus.notify_send(instructions, "", 2, 30, 0, true) {
|
||||||
&& let Ok(id) = sender.notify_send(instructions, "", 2, 0, 0, true)
|
notify = Some(id);
|
||||||
{
|
|
||||||
notify = Some((sender, id));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -96,8 +95,9 @@ pub(super) fn select_pw_screen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let result = f.await;
|
let result = f.await;
|
||||||
if let Some((sender, id)) = notify {
|
if let Some(id) = notify {
|
||||||
let _ = sender.notify_close(id);
|
//safe unwrap; checked above
|
||||||
|
let _ = app.dbus.notify_close(id);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ pub fn create_screen_renderer_wl(
|
|||||||
has_wlr_dmabuf: bool,
|
has_wlr_dmabuf: bool,
|
||||||
has_wlr_screencopy: bool,
|
has_wlr_screencopy: bool,
|
||||||
pw_token_store: &mut PwTokenMap,
|
pw_token_store: &mut PwTokenMap,
|
||||||
app: &AppState,
|
app: &mut AppState,
|
||||||
) -> Option<ScreenBackend> {
|
) -> Option<ScreenBackend> {
|
||||||
let mut capture: Option<ScreenBackend> = None;
|
let mut capture: Option<ScreenBackend> = None;
|
||||||
if (&*app.session.config.capture_method == "wlr-dmabuf") && has_wlr_dmabuf {
|
if (&*app.session.config.capture_method == "wlr-dmabuf") && has_wlr_dmabuf {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result<ScreenCreateDa
|
|||||||
let embed_mouse = !app.session.config.double_cursor_fix;
|
let embed_mouse = !app.session.config.double_cursor_fix;
|
||||||
|
|
||||||
let select_screen_result = select_pw_screen(
|
let select_screen_result = select_pw_screen(
|
||||||
|
app,
|
||||||
"Select ALL screens on the screencast pop-up!",
|
"Select ALL screens on the screencast pop-up!",
|
||||||
token,
|
token,
|
||||||
embed_mouse,
|
embed_mouse,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use crate::{
|
|||||||
config_io::{self, get_config_file_path},
|
config_io::{self, get_config_file_path},
|
||||||
graphics::WGfxExtras,
|
graphics::WGfxExtras,
|
||||||
gui,
|
gui,
|
||||||
subsystem::{audio::AudioOutput, input::HidWrapper},
|
subsystem::{audio::AudioOutput, dbus::DbusConnector, input::HidWrapper},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
@@ -49,6 +49,8 @@ pub struct AppState {
|
|||||||
|
|
||||||
pub wgui_globals: WguiGlobals,
|
pub wgui_globals: WguiGlobals,
|
||||||
|
|
||||||
|
pub dbus: DbusConnector,
|
||||||
|
|
||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
pub osc_sender: Option<OscSender>,
|
pub osc_sender: Option<OscSender>,
|
||||||
|
|
||||||
@@ -109,6 +111,8 @@ impl AppState {
|
|||||||
.and_then(|c| parse_color_hex(&c))
|
.and_then(|c| parse_color_hex(&c))
|
||||||
.unwrap_or(defaults.faded_color);
|
.unwrap_or(defaults.faded_color);
|
||||||
|
|
||||||
|
let dbus = DbusConnector::default();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
session,
|
session,
|
||||||
tasks,
|
tasks,
|
||||||
@@ -128,6 +132,7 @@ impl AppState {
|
|||||||
&WguiFontConfig::default(),
|
&WguiFontConfig::default(),
|
||||||
get_config_file_path(&theme),
|
get_config_file_path(&theme),
|
||||||
)?,
|
)?,
|
||||||
|
dbus,
|
||||||
|
|
||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
osc_sender,
|
osc_sender,
|
||||||
|
|||||||
133
wlx-overlay-s/src/subsystem/dbus/mod.rs
Normal file
133
wlx-overlay-s/src/subsystem/dbus/mod.rs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use dbus::{
|
||||||
|
Message,
|
||||||
|
arg::{PropMap, Variant},
|
||||||
|
blocking::Connection,
|
||||||
|
channel::MatchingReceiver,
|
||||||
|
message::MatchRule,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::subsystem::dbus::notifications::OrgFreedesktopNotifications;
|
||||||
|
|
||||||
|
mod notifications;
|
||||||
|
|
||||||
|
pub type DbusReceiveCallback = Box<dyn FnMut(Message, &Connection) -> bool + Send>;
|
||||||
|
pub type DbusMatchCallback = Box<dyn FnMut((), &Connection, &Message) -> bool + Send>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DbusConnector {
|
||||||
|
pub connection: Option<Connection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DbusConnector {
|
||||||
|
pub fn tick(&self) {
|
||||||
|
if let Some(c) = self.connection.as_ref() {
|
||||||
|
let _ = c.process(Duration::ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn become_monitor(
|
||||||
|
&mut self,
|
||||||
|
rule: MatchRule<'static>,
|
||||||
|
callback: DbusReceiveCallback,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let connection = self
|
||||||
|
.connection
|
||||||
|
.take()
|
||||||
|
.context("Not connected")
|
||||||
|
.or_else(|_| Connection::new_session())?;
|
||||||
|
|
||||||
|
let proxy = connection.with_proxy(
|
||||||
|
"org.freedesktop.DBus",
|
||||||
|
"/org/freedesktop/DBus",
|
||||||
|
Duration::from_millis(5000),
|
||||||
|
);
|
||||||
|
let result: Result<(), dbus::Error> = proxy.method_call(
|
||||||
|
"org.freedesktop.DBus.Monitoring",
|
||||||
|
"BecomeMonitor",
|
||||||
|
(vec![rule.match_str()], 0u32),
|
||||||
|
);
|
||||||
|
|
||||||
|
result?;
|
||||||
|
|
||||||
|
let _ = connection.start_receive(rule, callback);
|
||||||
|
|
||||||
|
self.connection = Some(connection);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_match(
|
||||||
|
&mut self,
|
||||||
|
rule: MatchRule<'static>,
|
||||||
|
callback: DbusMatchCallback,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let connection = self
|
||||||
|
.connection
|
||||||
|
.take()
|
||||||
|
.context("Not connected")
|
||||||
|
.or_else(|_| Connection::new_session())?;
|
||||||
|
|
||||||
|
let _ = connection.add_match(rule, callback)?;
|
||||||
|
self.connection = Some(connection);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify_send(
|
||||||
|
&mut self,
|
||||||
|
summary: &str,
|
||||||
|
body: &str,
|
||||||
|
urgency: u8,
|
||||||
|
timeout: i32,
|
||||||
|
replaces_id: u32,
|
||||||
|
transient: bool,
|
||||||
|
) -> anyhow::Result<u32> {
|
||||||
|
let connection = self
|
||||||
|
.connection
|
||||||
|
.take()
|
||||||
|
.context("Not connected")
|
||||||
|
.or_else(|_| Connection::new_session())?;
|
||||||
|
|
||||||
|
let proxy = 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)));
|
||||||
|
|
||||||
|
let retval = proxy.notify(
|
||||||
|
"WlxOverlay-S",
|
||||||
|
replaces_id,
|
||||||
|
"",
|
||||||
|
summary,
|
||||||
|
body,
|
||||||
|
vec![],
|
||||||
|
hints,
|
||||||
|
timeout,
|
||||||
|
)?;
|
||||||
|
self.connection = Some(connection);
|
||||||
|
|
||||||
|
Ok(retval)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify_close(&mut self, id: u32) -> anyhow::Result<()> {
|
||||||
|
let connection = self
|
||||||
|
.connection
|
||||||
|
.take()
|
||||||
|
.context("Not connected")
|
||||||
|
.or_else(|_| Connection::new_session())?;
|
||||||
|
let proxy = connection.with_proxy(
|
||||||
|
"org.freedesktop.Notifications",
|
||||||
|
"/org/freedesktop/Notifications",
|
||||||
|
Duration::from_millis(1000),
|
||||||
|
);
|
||||||
|
|
||||||
|
proxy.close_notification(id)?;
|
||||||
|
self.connection = Some(connection);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod audio;
|
pub mod audio;
|
||||||
|
pub mod dbus;
|
||||||
pub mod hid;
|
pub mod hid;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod notifications;
|
pub mod notifications;
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
#[allow(clippy::all)]
|
|
||||||
mod notifications_dbus;
|
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use dbus::{
|
use dbus::message::MatchRule;
|
||||||
arg::{PropMap, Variant},
|
|
||||||
blocking::Connection,
|
|
||||||
channel::MatchingReceiver,
|
|
||||||
message::MatchRule,
|
|
||||||
};
|
|
||||||
use notifications_dbus::OrgFreedesktopNotifications;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
sync::{
|
sync::{
|
||||||
@@ -20,12 +11,11 @@ use std::{
|
|||||||
};
|
};
|
||||||
use wlx_common::overlays::ToastTopic;
|
use wlx_common::overlays::ToastTopic;
|
||||||
|
|
||||||
use crate::{overlays::toast::Toast, state::AppState};
|
use crate::{overlays::toast::Toast, state::AppState, subsystem::dbus::DbusConnector};
|
||||||
|
|
||||||
pub struct NotificationManager {
|
pub struct NotificationManager {
|
||||||
rx_toast: mpsc::Receiver<Toast>,
|
rx_toast: mpsc::Receiver<Toast>,
|
||||||
tx_toast: mpsc::SyncSender<Toast>,
|
tx_toast: mpsc::SyncSender<Toast>,
|
||||||
dbus_data: Option<Connection>,
|
|
||||||
running: Arc<AtomicBool>,
|
running: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,16 +25,11 @@ impl NotificationManager {
|
|||||||
Self {
|
Self {
|
||||||
rx_toast,
|
rx_toast,
|
||||||
tx_toast,
|
tx_toast,
|
||||||
dbus_data: None,
|
|
||||||
running: Arc::new(AtomicBool::new(true)),
|
running: Arc::new(AtomicBool::new(true)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn submit_pending(&self, app: &mut AppState) {
|
pub fn submit_pending(&self, app: &mut AppState) {
|
||||||
if let Some(c) = &self.dbus_data {
|
|
||||||
let _ = c.process(Duration::ZERO);
|
|
||||||
}
|
|
||||||
|
|
||||||
if app.session.config.notifications_enabled {
|
if app.session.config.notifications_enabled {
|
||||||
self.rx_toast.try_iter().for_each(|toast| {
|
self.rx_toast.try_iter().for_each(|toast| {
|
||||||
toast.submit(app);
|
toast.submit(app);
|
||||||
@@ -55,78 +40,47 @@ impl NotificationManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_dbus(&mut self) {
|
pub fn run_dbus(&mut self, dbus: &mut DbusConnector) {
|
||||||
let Ok(conn) = Connection::new_session().context(
|
let rule = MatchRule::new_method_call()
|
||||||
"Failed to connect to dbus. Desktop notifications and keymap changes will not work.",
|
.with_member("Notify")
|
||||||
) else {
|
.with_interface("org.freedesktop.Notifications")
|
||||||
return;
|
.with_path("/org/freedesktop/Notifications");
|
||||||
};
|
|
||||||
|
|
||||||
let mut rule = MatchRule::new_method_call();
|
let sender = self.tx_toast.clone();
|
||||||
rule.member = Some("Notify".into());
|
if let Ok(_) = dbus
|
||||||
rule.interface = Some("org.freedesktop.Notifications".into());
|
.become_monitor(
|
||||||
rule.path = Some("/org/freedesktop/Notifications".into());
|
rule.clone(),
|
||||||
rule.eavesdrop = true;
|
|
||||||
|
|
||||||
let proxy = conn.with_proxy(
|
|
||||||
"org.freedesktop.DBus",
|
|
||||||
"/org/freedesktop/DBus",
|
|
||||||
Duration::from_millis(5000),
|
|
||||||
);
|
|
||||||
let result: Result<(), dbus::Error> = proxy.method_call(
|
|
||||||
"org.freedesktop.DBus.Monitoring",
|
|
||||||
"BecomeMonitor",
|
|
||||||
(vec![rule.match_str()], 0u32),
|
|
||||||
);
|
|
||||||
|
|
||||||
if matches!(result, Ok(())) {
|
|
||||||
let sender = self.tx_toast.clone();
|
|
||||||
conn.start_receive(
|
|
||||||
rule,
|
|
||||||
Box::new(move |msg, _| {
|
Box::new(move |msg, _| {
|
||||||
if let Ok(toast) = parse_dbus(&msg) {
|
if let Ok(toast) = parse_dbus(&msg) {
|
||||||
match sender.try_send(toast) {
|
let _ = sender
|
||||||
Ok(()) => {}
|
.try_send(toast)
|
||||||
Err(e) => {
|
.inspect_err(|e| log::error!("Failed to send notification: {e:?}"));
|
||||||
log::error!("Failed to send notification: {e:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
log::info!("Listening to DBus notifications via BecomeMonitor.");
|
.context("Could not register BecomeMonitor")
|
||||||
} else {
|
.inspect_err(|e| log::warn!("{e:?}"))
|
||||||
let rule_with_eavesdrop = {
|
{
|
||||||
let mut rule = rule.clone();
|
log::info!("Listening to D-Bus notifications via BecomeMonitor.");
|
||||||
rule.eavesdrop = true;
|
return;
|
||||||
rule
|
|
||||||
};
|
|
||||||
|
|
||||||
let sender2 = self.tx_toast.clone();
|
|
||||||
let result = conn.add_match(rule_with_eavesdrop, move |(): (), _, msg| {
|
|
||||||
if let Ok(toast) = parse_dbus(msg) {
|
|
||||||
match sender2.try_send(toast) {
|
|
||||||
Ok(()) => {}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to send notification: {e:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
});
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(_) => {
|
|
||||||
log::info!("Listening to DBus notifications via eavesdrop.");
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
log::error!("Failed to add DBus match. Desktop notifications will not work.",);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dbus_data = Some(conn);
|
let sender = self.tx_toast.clone();
|
||||||
|
let _ = dbus
|
||||||
|
.add_match(
|
||||||
|
rule.with_eavesdrop(),
|
||||||
|
Box::new(move |(), _, msg| {
|
||||||
|
if let Ok(toast) = parse_dbus(msg) {
|
||||||
|
let _ = sender
|
||||||
|
.try_send(toast)
|
||||||
|
.inspect_err(|e| log::error!("Failed to send notification: {e:?}"));
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.context("Failed to register D-Bus notifications. Desktop notifications won't work.")
|
||||||
|
.inspect_err(|e| log::warn!("{e:?}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_udp(&mut self) {
|
pub fn run_udp(&mut self) {
|
||||||
@@ -195,60 +149,6 @@ 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> {
|
fn parse_dbus(msg: &dbus::Message) -> anyhow::Result<Toast> {
|
||||||
let mut args = msg.iter_init();
|
let mut args = msg.iter_init();
|
||||||
let app_name: String = args.read()?;
|
let app_name: String = args.read()?;
|
||||||
Reference in New Issue
Block a user