use crate::client::Client;
use crate::client::LookupError;
use crate::ifs::wl_output::WlOutput;
use crate::leaks::Tracker;
use crate::object::BreakLoops;
use crate::object::Version;
use crate::tree::Direction;
use crate::tree::OutputNode;
use crate::tree::OutputNodeId;
use crate::tree::ToplevelOpt;
use crate::tree::TreeTimeline::LiveTL;
use crate::wire::ZwlrForeignToplevelHandleV1Id;
use crate::wire::zwlr_foreign_toplevel_handle_v1::*;
use arrayvec::ArrayVec;
use jay_proc::Object;
use std::cell::Cell;
use std::rc::Rc;
const STATE_ACTIVATED: u32 = 2;
const STATE_FULLSCREEN: u32 = 3;
const FULLSCREEN_SINCE: Version = Version(2);
#[derive(Object)]
#[break_loops]
pub struct ZwlrForeignToplevelHandleV1 {
pub id: ZwlrForeignToplevelHandleV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub toplevel: ToplevelOpt,
pub version: Version,
pub output: Cell<OutputNodeId>,
}
impl ZwlrForeignToplevelHandleV1 {
fn detach(&self) {
if let Some(tl) = self.toplevel.get() {
tl.tl_data()
.manager_handles
.remove(&(self.client.id, self.id));
}
}
}
impl ZwlrForeignToplevelHandleV1RequestHandler for ZwlrForeignToplevelHandleV1 {
type Error = LookupError;
fn set_maximized(&self, _req: SetMaximized, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn unset_maximized(&self, _req: UnsetMaximized, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn set_minimized(&self, _req: SetMinimized, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn unset_minimized(&self, _req: UnsetMinimized, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn activate(&self, req: Activate, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if let Some(toplevel) = self.toplevel.get() {
if !toplevel.node_visible(LiveTL) {
toplevel.clone().node_make_visible_dyn();
if !toplevel.node_visible(LiveTL) {
return Ok(());
}
}
let seat = self.client.lookup(req.seat)?;
toplevel.node_do_focus_dyn(&seat.global, Direction::Unspecified);
seat.global.maybe_schedule_warp_mouse_to_focus();
}
Ok(())
}
fn close(&self, _req: Close, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if let Some(toplevel) = self.toplevel.get() {
toplevel.tl_close();
}
Ok(())
}
fn set_rectangle(&self, _req: SetRectangle, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.detach();
self.client.remove_obj(self);
Ok(())
}
fn set_fullscreen(&self, req: SetFullscreen, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if let Some(toplevel) = self.toplevel.get() {
let ws = if req.output.is_some() {
self.client
.lookup(req.output)?
.global
.node()
.map(|node| node.ensure_normal_workspace())
} else {
None
};
toplevel.tl_set_fullscreen(true, ws);
}
Ok(())
}
fn unset_fullscreen(&self, _req: UnsetFullscreen, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if let Some(toplevel) = self.toplevel.get() {
toplevel.tl_set_fullscreen(false, None);
}
Ok(())
}
}
impl ZwlrForeignToplevelHandleV1 {
pub fn leave_output(&self, output: &Rc<OutputNode>) {
self.output.set(OutputNodeId::none());
let bindings = output.global.bindings.borrow();
if let Some(bindings) = bindings.get(&self.client.id) {
for binding in bindings.values() {
self.send_output_leave(binding);
}
}
}
pub fn enter_output(&self, output: &Rc<OutputNode>) {
self.output.set(output.id);
let bindings = output.global.bindings.borrow();
if let Some(bindings) = bindings.get(&self.client.id) {
for binding in bindings.values() {
self.send_output_enter(binding);
}
}
}
pub fn send_closed(&self) {
self.client.event(Closed { self_id: self.id });
}
pub fn send_done(&self) {
self.client.event(Done { self_id: self.id });
}
pub fn send_title(&self, title: &str) {
self.client.event(Title {
self_id: self.id,
title,
});
}
pub fn send_app_id(&self, app_id: &str) {
self.client.event(AppId {
self_id: self.id,
app_id,
});
}
pub fn send_state(&self, activated: bool, fullscreen: bool) {
let mut state: ArrayVec<u32, 2> = ArrayVec::new();
if activated {
state.push(STATE_ACTIVATED);
}
if self.version >= FULLSCREEN_SINCE {
if fullscreen {
state.push(STATE_FULLSCREEN);
}
}
self.client.event(State {
self_id: self.id,
state: &state,
});
}
#[expect(unused)]
pub fn send_parent(&self, parent: &Rc<ZwlrForeignToplevelHandleV1>) {
self.client.event(Parent {
self_id: self.id,
parent: parent.id,
});
}
pub fn send_output_enter(&self, output: &Rc<WlOutput>) {
self.client.event(OutputEnter {
self_id: self.id,
output: output.id,
});
}
fn send_output_leave(&self, output: &Rc<WlOutput>) {
self.client.event(OutputLeave {
self_id: self.id,
output: output.id,
});
}
}
impl BreakLoops for ZwlrForeignToplevelHandleV1 {
fn break_loops(self: Rc<Self>) {
self.detach();
}
}