1
0
Fork 0
forked from wry/wry

implement zwlr_foreign_toplevel_management protocol (#452)

* implement zwlr_foreign_toplevel_management protocol

* check if initial id is empty
This commit is contained in:
Mostafa Ibrahim 2025-05-28 14:53:29 +03:00 committed by GitHub
parent 3be8534683
commit 0930f00356
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 636 additions and 24 deletions

View file

@ -20,6 +20,8 @@ use {
WlSurface, x_surface::xwindow::XwindowData,
xdg_surface::xdg_toplevel::XdgToplevelToplevelData,
},
zwlr_foreign_toplevel_handle_v1::ZwlrForeignToplevelHandleV1,
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1,
},
rect::Rect,
state::State,
@ -38,11 +40,12 @@ use {
},
wire::{
ExtForeignToplevelHandleV1Id, ExtImageCopyCaptureSessionV1Id, JayScreencastId,
JayToplevelId,
JayToplevelId, ZwlrForeignToplevelHandleV1Id,
},
},
jay_config::{window, window::WindowType},
std::{
borrow::Borrow,
cell::{Cell, RefCell},
ops::Deref,
rc::{Rc, Weak},
@ -53,12 +56,12 @@ tree_id!(ToplevelNodeId);
pub trait ToplevelNode: ToplevelNodeBase {
fn tl_surface_active_changed(&self, active: bool);
fn tl_set_fullscreen(self: Rc<Self>, fullscreen: bool);
fn tl_set_fullscreen(self: Rc<Self>, fullscreen: bool, ws: Option<Rc<WorkspaceNode>>);
fn tl_title_changed(&self);
fn tl_set_parent(&self, parent: Rc<dyn ContainingNode>);
fn tl_extents_changed(&self);
fn tl_set_workspace(&self, ws: &Rc<WorkspaceNode>);
fn tl_workspace_output_changed(&self);
fn tl_workspace_output_changed(&self, prev: &Rc<OutputNode>, new: &Rc<OutputNode>);
fn tl_change_extents(self: Rc<Self>, rect: &Rect);
fn tl_set_visible(&self, visible: bool);
fn tl_destroy(&self);
@ -74,10 +77,10 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
});
}
fn tl_set_fullscreen(self: Rc<Self>, fullscreen: bool) {
fn tl_set_fullscreen(self: Rc<Self>, fullscreen: bool, ws: Option<Rc<WorkspaceNode>>) {
let data = self.tl_data();
if fullscreen {
if let Some(ws) = data.workspace.get() {
if let Some(ws) = ws.or_else(|| data.workspace.get()) {
data.set_fullscreen2(&data.state, self.clone(), &ws);
}
} else {
@ -132,14 +135,17 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
let prev = data.workspace.set(Some(ws.clone()));
self.tl_set_workspace_ext(ws);
self.tl_data().property_changed(TL_CHANGED_WORKSPACE);
let prev_id = prev.map(|p| p.output.get().id);
let new_id = Some(ws.output.get().id);
if prev_id != new_id {
self.tl_workspace_output_changed();
let prev_output = match &prev {
Some(n) => n.output.get(),
_ => ws.state.dummy_output.get().unwrap(),
};
let new_output = ws.output.get();
if prev.is_none() || prev_output.id != new_output.id {
self.tl_workspace_output_changed(&prev_output, &new_output);
}
}
fn tl_workspace_output_changed(&self) {
fn tl_workspace_output_changed(&self, prev: &Rc<OutputNode>, new: &Rc<OutputNode>) {
let data = self.tl_data();
for sc in data.jay_screencasts.lock().values() {
sc.update_latch_listener();
@ -147,6 +153,13 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
for sc in data.ext_copy_sessions.lock().values() {
sc.update_latch_listener();
}
if prev.id != new.id {
for handle in data.manager_handles.borrow().lock().values() {
handle.leave_output(prev);
handle.enter_output(new);
handle.send_done();
}
}
}
fn tl_change_extents(self: Rc<Self>, rect: &Rect) {
@ -322,6 +335,8 @@ pub struct ToplevelData {
pub identifier: Cell<ToplevelIdentifier>,
pub handles:
CopyHashMap<(ClientId, ExtForeignToplevelHandleV1Id), Rc<ExtForeignToplevelHandleV1>>,
pub manager_handles:
CopyHashMap<(ClientId, ZwlrForeignToplevelHandleV1Id), Rc<ZwlrForeignToplevelHandleV1>>,
pub render_highlight: NumCell<u32>,
pub jay_toplevels: CopyHashMap<(ClientId, JayToplevelId), Rc<JayToplevel>>,
pub jay_screencasts: CopyHashMap<(ClientId, JayScreencastId), Rc<JayScreencast>>,
@ -372,6 +387,7 @@ impl ToplevelData {
app_id: Default::default(),
identifier: Cell::new(id),
handles: Default::default(),
manager_handles: Default::default(),
render_highlight: Default::default(),
jay_toplevels: Default::default(),
jay_screencasts: Default::default(),
@ -397,6 +413,10 @@ impl ToplevelData {
if let Some(parent) = self.parent.get() {
parent.node_child_active_changed(tl, active_new, 1);
}
for handle in self.manager_handles.borrow().lock().values() {
handle.send_state(active_new, self.is_fullscreen.get());
handle.send_done();
}
}
}
@ -453,6 +473,12 @@ impl ToplevelData {
handle.send_closed();
}
}
{
let mut manager_handles = self.manager_handles.lock();
for handle in manager_handles.drain_values() {
handle.send_closed();
}
}
self.detach_node(node);
self.property_changed(TL_CHANGED_DESTROYED);
}
@ -472,9 +498,29 @@ impl ToplevelData {
let id = self.identifier.get().to_string();
let title = self.title.borrow();
let app_id = self.app_id.borrow();
let activated = self.active();
let fullscreen = self.is_fullscreen.get();
let class;
let manager_app_id = match &self.kind {
ToplevelType::XWindow(w) => {
class = w.info.class.borrow();
class.as_deref().unwrap_or_default()
}
_ => &app_id,
};
for list in self.state.toplevel_lists.lock().values() {
self.send_once(&toplevel, list, &id, &title, &app_id);
}
for manager in self.state.toplevel_managers.lock().values() {
self.manager_send_once(
&toplevel,
manager,
&title,
manager_app_id,
activated,
fullscreen,
);
}
}
pub fn send(&self, toplevel: Rc<dyn ToplevelNode>, list: &ExtForeignToplevelListV1) {
@ -508,12 +554,76 @@ impl ToplevelData {
.set((handle.client.id, handle.id), handle.clone());
}
pub fn manager_send(
&self,
toplevel: Rc<dyn ToplevelNode>,
manager: &ZwlrForeignToplevelManagerV1,
) {
let title = self.title.borrow();
let activated = self.active();
let fullscreen = self.is_fullscreen.get();
let app_id;
let class;
let manager_app_id = match &self.kind {
ToplevelType::XWindow(w) => {
class = w.info.class.borrow();
class.as_deref().unwrap_or_default()
}
_ => {
app_id = self.app_id.borrow();
&app_id
}
};
self.manager_send_once(
&toplevel,
manager,
&title,
manager_app_id,
activated,
fullscreen,
);
}
fn manager_send_once(
&self,
toplevel: &Rc<dyn ToplevelNode>,
manager: &ZwlrForeignToplevelManagerV1,
title: &str,
app_id: &str,
activated: bool,
fullscreen: bool,
) {
let opt = ToplevelOpt {
toplevel: Rc::downgrade(toplevel),
identifier: self.identifier.get(),
};
let handle = match manager.publish_toplevel(opt) {
None => return,
Some(handle) => handle,
};
if !app_id.is_empty() {
handle.send_app_id(app_id);
}
if !title.is_empty() {
handle.send_title(title);
}
handle.enter_output(&self.output());
handle.send_state(activated, fullscreen);
handle.send_done();
self.manager_handles
.set((handle.client.id, handle.id), handle.clone());
}
pub fn set_title(&self, title: &str) {
*self.title.borrow_mut() = title.to_string();
for handle in self.handles.lock().values() {
handle.send_title(title);
handle.send_done();
}
for handle in self.manager_handles.lock().values() {
handle.send_title(title);
handle.send_done();
}
}
pub fn set_app_id(&self, app_id: &str) {
@ -526,6 +636,10 @@ impl ToplevelData {
handle.send_app_id(app_id);
handle.send_done();
}
for handle in self.manager_handles.lock().values() {
handle.send_app_id(app_id);
handle.send_done();
}
self.property_changed(TL_CHANGED_APP_ID)
}
@ -596,6 +710,10 @@ impl ToplevelData {
for seat in kb_foci {
node.clone().node_do_focus(&seat, Direction::Unspecified);
}
for handle in self.manager_handles.lock().values() {
handle.send_state(self.active(), true);
handle.send_done();
}
}
pub fn unset_fullscreen(&self, state: &Rc<State>, node: Rc<dyn ToplevelNode>) {
@ -641,6 +759,10 @@ impl ToplevelData {
}
}
fd.placeholder.tl_destroy();
for handle in self.manager_handles.lock().values() {
handle.send_state(self.active(), false);
handle.send_done();
}
}
pub fn set_visible(&self, node: &dyn Node, visible: bool) {