implement zwlr_foreign_toplevel_management protocol (#452)
* implement zwlr_foreign_toplevel_management protocol * check if initial id is empty
This commit is contained in:
parent
3be8534683
commit
0930f00356
18 changed files with 636 additions and 24 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ impl WorkspaceNode {
|
|||
}
|
||||
|
||||
pub fn set_output(&self, output: &Rc<OutputNode>) {
|
||||
self.output.set(output.clone());
|
||||
let old = self.output.set(output.clone());
|
||||
for wh in self.ext_workspaces.lock().values() {
|
||||
wh.handle_new_output(output);
|
||||
}
|
||||
|
|
@ -111,38 +111,44 @@ impl WorkspaceNode {
|
|||
jw.send_output(output);
|
||||
}
|
||||
self.update_has_captures();
|
||||
struct OutputSetter<'a>(&'a Rc<OutputNode>);
|
||||
struct OutputSetter<'a> {
|
||||
old: &'a Rc<OutputNode>,
|
||||
new: &'a Rc<OutputNode>,
|
||||
}
|
||||
impl NodeVisitorBase for OutputSetter<'_> {
|
||||
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
||||
node.set_output(self.0);
|
||||
node.set_output(self.new);
|
||||
}
|
||||
|
||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||
node.tl_workspace_output_changed();
|
||||
node.tl_workspace_output_changed(self.old, self.new);
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>) {
|
||||
node.tl_workspace_output_changed();
|
||||
node.tl_workspace_output_changed(self.old, self.new);
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||
node.after_ws_move(self.0);
|
||||
node.after_ws_move(self.new);
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_xwindow(&mut self, node: &Rc<Xwindow>) {
|
||||
node.tl_workspace_output_changed();
|
||||
node.tl_workspace_output_changed(self.old, self.new);
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_placeholder(&mut self, node: &Rc<PlaceholderNode>) {
|
||||
node.tl_workspace_output_changed();
|
||||
node.tl_workspace_output_changed(self.old, self.new);
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
}
|
||||
let mut visitor = OutputSetter(output);
|
||||
let mut visitor = OutputSetter {
|
||||
old: &old,
|
||||
new: output,
|
||||
};
|
||||
self.node_visit_children(&mut visitor);
|
||||
for stacked in self.stacked.iter() {
|
||||
stacked.deref().clone().node_visit(&mut visitor);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue