use crate::client::Client;
use crate::client::LookupError;
use crate::leaks::Tracker;
use crate::object::BreakLoops;
use crate::object::Version;
use crate::sm::Session;
use crate::sm::SessionGetStatus;
use crate::sm::SessionManagementError;
use crate::sm::SessionName;
use crate::sm::SessionOwner;
use crate::utils::clonecell::CloneCell;
use crate::utils::linkedlist::LinkedNode;
use crate::wire::XdgSessionV1Id;
use crate::wire::xdg_session_v1::AddToplevel;
use crate::wire::xdg_session_v1::Created;
use crate::wire::xdg_session_v1::Destroy;
use crate::wire::xdg_session_v1::Remove;
use crate::wire::xdg_session_v1::RemoveToplevel;
use crate::wire::xdg_session_v1::Replaced;
use crate::wire::xdg_session_v1::RestoreToplevel;
use crate::wire::xdg_session_v1::Restored;
use crate::wire::xdg_session_v1::XdgSessionV1RequestHandler;
use jay_proc::Object;
use std::cell::RefCell;
use std::error::Error;
use std::rc::Rc;
use thiserror::Error;
#[derive(Object)]
#[break_loops]
pub struct XdgSessionV1 {
pub id: XdgSessionV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub version: Version,
pub session: CloneCell<Option<Rc<Session>>>,
pub name: SessionName,
pub link: RefCell<Option<LinkedNode<Rc<Self>>>>,
}
impl XdgSessionV1 {
fn disown_(&self, to_peer: bool) {
if let Some(session) = self.session.take() {
if to_peer {
session.disown_from_peer();
}
}
if self.link.take().is_some() {
self.client.num_live_sessions.fetch_sub(1);
}
}
pub fn disown_to_peer(&self) {
self.disown_(true);
}
pub fn bump(&self) {
if let Some(link) = &*self.link.borrow() {
self.client.live_sessions.add_last_existing(link);
}
}
}
impl SessionOwner for XdgSessionV1 {
fn client(&self) -> Option<&Rc<Client>> {
Some(&self.client)
}
fn loaded(&self, status: SessionGetStatus) {
match status {
SessionGetStatus::Created => self.send_created(self.name),
SessionGetStatus::Restored => self.send_restored(),
}
}
fn error(&self, e: &dyn Error) {
self.client.error(e);
}
fn disown_from_peer(&self, replaced: bool) {
if replaced {
self.send_replaced();
}
self.disown_(false);
}
}
impl XdgSessionV1 {
pub fn send_created(&self, name: SessionName) {
self.client.event(Created {
self_id: self.id,
session_id: &name.to_string(),
});
}
pub fn send_restored(&self) {
self.client.event(Restored { self_id: self.id });
}
pub fn send_replaced(&self) {
self.client.event(Replaced { self_id: self.id });
}
}
impl XdgSessionV1RequestHandler for XdgSessionV1 {
type Error = XdgSessionV1Error;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.disown_to_peer();
self.client.remove_obj(self);
Ok(())
}
fn remove(&self, _req: Remove, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if let Some(session) = self.session.get() {
session.remove();
}
self.disown_from_peer(false);
self.client.remove_obj(self);
Ok(())
}
fn add_toplevel(&self, req: AddToplevel<'_>, slf: &Rc<Self>) -> Result<(), Self::Error> {
slf.create_session(req.id, req.toplevel, false, req.name)
}
fn restore_toplevel(
&self,
req: RestoreToplevel<'_>,
slf: &Rc<Self>,
) -> Result<(), Self::Error> {
slf.create_session(req.id, req.toplevel, true, req.name)
}
fn remove_toplevel(&self, req: RemoveToplevel<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.bump();
if let Some(session) = self.session.get() {
session.remove_toplevel(req.name);
}
Ok(())
}
}
impl BreakLoops for XdgSessionV1 {
fn break_loops(self: Rc<Self>) {
self.disown_to_peer();
}
}
#[derive(Debug, Error)]
pub enum XdgSessionV1Error {
#[error(transparent)]
Lookup(#[from] LookupError),
#[error("The toplevel is already part of a session")]
HasSession,
#[error("The toplevel has already been committed")]
Committed,
#[error(transparent)]
SessionManagementError(#[from] SessionManagementError),
}