use nix::libc::pid_t;
use pinenote_service::types::{Rect, rockchip_ebc::Hint};
use serde::Deserialize;
use tokio::sync::{mpsc, oneshot};
use zbus::{
fdo, interface,
zvariant::{Type, Value},
};
use crate::{dbus, ebc};
#[derive(Type, Value, Deserialize)]
struct Window {
title: String,
area: Rect,
hint: String,
visible: bool,
fullscreen: bool,
z_index: i32,
}
pub struct HintMgr1 {
tx: ebc::CommandSender,
}
impl HintMgr1 {
pub fn new(tx: mpsc::Sender<ebc::Command>) -> Self {
Self { tx: tx.into() }
}
async fn send_win(&self, win: ebc::Window) -> fdo::Result<()> {
self.tx.send(win).await.map_err(dbus::internal_error)
}
}
fn parse_hint(hint: String) -> fdo::Result<Option<Hint>> {
let ret = if hint.is_empty() {
None
} else {
Some(
Hint::try_from_human_readable(hint.as_str())
.map_err(|_| fdo::Error::InvalidArgs(format!("Unrecognized Hint {hint}")))?,
)
};
Ok(ret)
}
fn validate_rect(rect: Rect) -> fdo::Result<Rect> {
let Rect { x1, y1, x2, y2 } = rect;
if x1 < 0 || y1 < 0 || x1 > x2 || y1 > y2 {
Err(fdo::Error::InvalidArgs("Bad Rectangle".into()))
} else {
Ok(Rect { x1, y1, x2, y2 })
}
}
#[interface(name = "org.pinenote.HintMgr1")]
impl HintMgr1 {
async fn app_register(&self, pid: i32) -> fdo::Result<String> {
let (tx, rx) = oneshot::channel::<String>();
if pid <= 0 {
return Err(fdo::Error::UnixProcessIdUnknown(format!("Bad PID {pid}")));
}
let pid: pid_t = pid;
self.tx
.with_reply(ebc::Application::Add(pid, tx), rx)
.await
.map_err(dbus::internal_error)
}
async fn app_remove(&self, app_key: String) -> fdo::Result<()> {
self.tx
.send(ebc::Application::Remove(app_key))
.await
.map_err(dbus::internal_error)
}
async fn window_add(&self, app_key: String, win: Window) -> fdo::Result<String> {
let (reply, rx) = oneshot::channel::<String>();
let Window {
title,
area,
hint,
visible,
fullscreen,
z_index,
} = win;
let hint = parse_hint(hint)?;
let area = validate_rect(area)?;
let add = ebc::Window::Add {
app_key,
title,
area,
hint,
visible,
fullscreen,
z_index,
reply,
};
self.tx
.with_reply(add, rx)
.await
.map_err(dbus::internal_error)
}
async fn window_update(&self, win_key: String, win: Window) -> fdo::Result<()> {
let Window {
title,
area,
hint,
visible,
fullscreen,
z_index,
} = win;
let hint = parse_hint(hint)?;
let area = validate_rect(area)?;
let update = ebc::WindowUpdate {
title: Some(title),
area: Some(area),
hint: Some(hint),
visible: Some(visible),
fullscreen: Some(fullscreen),
z_index: Some(z_index),
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_update_title(&self, win_key: String, title: String) -> fdo::Result<()> {
let update = ebc::WindowUpdate {
title: Some(title),
..Default::default()
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_update_area(&self, win_key: String, area: Rect) -> fdo::Result<()> {
let area = validate_rect(area)?;
let update = ebc::WindowUpdate {
area: Some(area),
..Default::default()
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_update_hint(&self, win_key: String, hint: String) -> fdo::Result<()> {
let hint = parse_hint(hint)?;
let update = ebc::WindowUpdate {
hint: Some(hint),
..Default::default()
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_update_visible(&self, win_key: String, visible: bool) -> fdo::Result<()> {
let update = ebc::WindowUpdate {
visible: Some(visible),
..Default::default()
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_update_fullscreen(&self, win_key: String, fullscreen: bool) -> fdo::Result<()> {
let update = ebc::WindowUpdate {
fullscreen: Some(fullscreen),
..Default::default()
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_update_zindex(&self, win_key: String, z_index: i32) -> fdo::Result<()> {
let update = ebc::WindowUpdate {
z_index: Some(z_index),
..Default::default()
};
self.send_win(ebc::Window::Update { win_key, update }).await
}
async fn window_remove(&self, key: String) -> fdo::Result<()> {
self.send_win(ebc::Window::Remove(key)).await
}
}