1
0
Fork 0
forked from wry/wry

wayland: implement xdg-activation

This commit is contained in:
Julian Orth 2024-02-14 17:42:59 +01:00
parent 0628a9d393
commit 41d7531cd5
26 changed files with 667 additions and 50 deletions

View file

@ -24,6 +24,7 @@ use {
rc_eq::rc_eq,
scroller::Scroller,
smallmap::{SmallMap, SmallMapMut},
threshold_counter::ThresholdCounter,
},
},
ahash::AHashMap,
@ -83,6 +84,7 @@ pub struct ContainerTitle {
pub struct ContainerRenderData {
pub title_rects: Vec<Rect>,
pub active_title_rects: Vec<Rect>,
pub attention_title_rects: Vec<Rect>,
pub last_active_rect: Option<Rect>,
pub border_rects: Vec<Rect>,
pub underline_rects: Vec<Rect>,
@ -115,6 +117,7 @@ pub struct ContainerNode {
pub render_data: RefCell<ContainerRenderData>,
scroller: Scroller,
toplevel_data: ToplevelData,
attention_requests: ThresholdCounter,
}
impl Debug for ContainerNode {
@ -126,6 +129,7 @@ impl Debug for ContainerNode {
pub struct ContainerChild {
pub node: Rc<dyn ToplevelNode>,
pub active: Cell<bool>,
pub attention_requested: Cell<bool>,
title: RefCell<String>,
pub title_tex: SmallMap<Scale, TextTexture, 2>,
pub title_rect: Cell<Rect>,
@ -172,21 +176,21 @@ impl ContainerNode {
) -> Rc<Self> {
child.clone().tl_set_workspace(workspace);
let children = LinkedList::new();
let child_node = children.add_last(ContainerChild {
node: child.clone(),
active: Default::default(),
body: Default::default(),
content: Default::default(),
factor: Cell::new(1.0),
title: Default::default(),
title_tex: Default::default(),
title_rect: Default::default(),
focus_history: Default::default(),
attention_requested: Cell::new(false),
});
let child_node_ref = child_node.clone();
let mut child_nodes = AHashMap::new();
child_nodes.insert(
child.node_id(),
children.add_last(ContainerChild {
node: child.clone(),
active: Default::default(),
body: Default::default(),
content: Default::default(),
factor: Cell::new(1.0),
title: Default::default(),
title_tex: Default::default(),
title_rect: Default::default(),
focus_history: Default::default(),
}),
);
child_nodes.insert(child.node_id(), child_node);
let slf = Rc::new(Self {
id: state.node_ids.next(),
parent: CloneCell::new(parent.clone()),
@ -213,9 +217,11 @@ impl ContainerNode {
render_data: Default::default(),
scroller: Default::default(),
toplevel_data: ToplevelData::new(state, Default::default(), None),
attention_requests: Default::default(),
});
slf.tl_set_parent(parent);
child.tl_set_parent(slf.clone());
slf.apply_child_flags(&child_node_ref);
slf
}
@ -293,11 +299,13 @@ impl ContainerNode {
title_tex: Default::default(),
title_rect: Default::default(),
focus_history: Default::default(),
attention_requested: Default::default(),
});
let r = link.to_ref();
links.insert(new.node_id(), link);
r
};
self.apply_child_flags(&new_ref);
new.clone().tl_set_workspace(&self.workspace.get());
new.tl_set_parent(self.clone());
new.tl_set_visible(self.toplevel_data.visible.get());
@ -644,6 +652,7 @@ impl ContainerNode {
}
rd.title_rects.clear();
rd.active_title_rects.clear();
rd.attention_title_rects.clear();
rd.border_rects.clear();
rd.underline_rects.clear();
rd.last_active_rect.take();
@ -667,6 +676,9 @@ impl ContainerNode {
let color = if child.active.get() {
rd.active_title_rects.push(rect);
theme.colors.focused_title_text.get()
} else if child.attention_requested.get() {
rd.attention_title_rects.push(rect);
theme.colors.unfocused_title_text.get()
} else if !have_active && last_active == Some(child.node.node_id()) {
rd.last_active_rect = Some(rect);
theme.colors.focused_inactive_title_text.get()
@ -760,7 +772,7 @@ impl ContainerNode {
return;
}
let child = {
let children = self.child_nodes.borrow_mut();
let children = self.child_nodes.borrow();
match child {
Some(c) => match children.get(&c.node_id()) {
Some(c) => Some(c.to_ref()),
@ -815,7 +827,7 @@ impl ContainerNode {
child: &dyn ToplevelNode,
direction: Direction,
) {
let child = match self.child_nodes.borrow_mut().get(&child.node_id()) {
let child = match self.child_nodes.borrow().get(&child.node_id()) {
Some(c) => c.to_ref(),
_ => return,
};
@ -880,7 +892,7 @@ impl ContainerNode {
if split == self.split.get()
|| (split == ContainerSplit::Horizontal && self.mono_child.get().is_some())
{
let cc = match self.child_nodes.borrow_mut().get(&child.node_id()) {
let cc = match self.child_nodes.borrow().get(&child.node_id()) {
Some(l) => l.to_ref(),
None => return,
};
@ -934,6 +946,33 @@ impl ContainerNode {
self.prepend_child(node);
}
}
fn apply_child_flags(&self, child: &ContainerChild) {
let data = child.node.tl_data();
let attention_requested = data.wants_attention.get();
child.attention_requested.set(attention_requested);
if attention_requested {
self.mod_attention_requests(true);
}
}
fn discard_child_flags(&self, child: &ContainerChild) {
if child.attention_requested.get() {
self.mod_attention_requests(false);
}
}
fn mod_attention_requests(&self, set: bool) {
let propagate = self.attention_requests.adj(set);
if set || propagate {
self.toplevel_data.wants_attention.set(set);
}
if propagate {
self.parent
.get()
.cnode_child_attention_request_changed(self, set);
}
}
}
struct SeatOp {
@ -999,7 +1038,7 @@ impl Node for ContainerNode {
}
fn node_child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) {
let child = match self.child_nodes.borrow_mut().get(&child.node_id()) {
let child = match self.child_nodes.borrow().get(&child.node_id()) {
Some(cn) => cn.to_ref(),
_ => return,
};
@ -1083,7 +1122,7 @@ impl Node for ContainerNode {
}
fn node_child_active_changed(self: Rc<Self>, child: &dyn Node, active: bool, depth: u32) {
let node = match self.child_nodes.borrow_mut().get(&child.node_id()) {
let node = match self.child_nodes.borrow().get(&child.node_id()) {
Some(l) => l.to_ref(),
None => return,
};
@ -1276,6 +1315,7 @@ impl ContainingNode for ContainerNode {
None => (false, false),
Some(mc) => (true, mc.node.node_id() == old.node_id()),
};
self.discard_child_flags(&node);
let link = node.append(ContainerChild {
node: new.clone(),
active: Cell::new(false),
@ -1286,7 +1326,9 @@ impl ContainingNode for ContainerNode {
title_tex: Default::default(),
title_rect: Cell::new(node.title_rect.get()),
focus_history: Cell::new(None),
attention_requested: Cell::new(false),
});
self.apply_child_flags(&link);
if let Some(fh) = node.focus_history.take() {
link.focus_history.set(Some(fh.append(link.to_ref())));
}
@ -1314,6 +1356,7 @@ impl ContainingNode for ContainerNode {
None => return,
};
node.focus_history.set(None);
self.discard_child_flags(&node);
if let Some(mono) = self.mono_child.get() {
if mono.node.node_id() == child.node_id() {
let mut new = self.focus_history.last().map(|n| n.deref().clone());
@ -1364,6 +1407,19 @@ impl ContainingNode for ContainerNode {
fn cnode_accepts_child(&self, _node: &dyn Node) -> bool {
true
}
fn cnode_child_attention_request_changed(self: Rc<Self>, child: &dyn Node, set: bool) {
let children = self.child_nodes.borrow();
let child = match children.get(&child.node_id()) {
Some(c) => c,
_ => return,
};
if child.attention_requested.replace(set) == set {
return;
}
self.mod_attention_requests(set);
self.schedule_compute_render_data();
}
}
impl ToplevelNode for ContainerNode {

View file

@ -14,4 +14,5 @@ pub trait ContainingNode: Node {
}
fn cnode_remove_child2(self: Rc<Self>, child: &dyn Node, preserve_focus: bool);
fn cnode_accepts_child(&self, node: &dyn Node) -> bool;
fn cnode_child_attention_request_changed(self: Rc<Self>, child: &dyn Node, set: bool);
}

View file

@ -45,6 +45,7 @@ pub struct FloatNode {
pub title: RefCell<String>,
pub title_textures: CopyHashMap<Scale, TextTexture>,
seats: RefCell<AHashMap<SeatId, SeatState>>,
pub attention_requested: Cell<bool>,
}
struct SeatState {
@ -112,7 +113,9 @@ impl FloatNode {
title: Default::default(),
title_textures: Default::default(),
seats: Default::default(),
attention_requested: Cell::new(false),
});
floater.apply_child_flags();
floater
.display_link
.set(Some(state.root.stacked.add_last(floater.clone())));
@ -345,6 +348,29 @@ impl FloatNode {
self.workspace.set(ws.clone());
self.stacked_set_visible(ws.stacked_visible());
}
fn apply_child_flags(&self) {
let child = match self.child.get() {
None => return,
Some(c) => c,
};
let data = child.tl_data();
let activation_requested = data.wants_attention.get();
self.attention_requested.set(activation_requested);
if activation_requested {
self.workspace
.get()
.cnode_child_attention_request_changed(self, true);
}
}
fn discard_child_flags(&self) {
if self.attention_requested.get() {
self.workspace
.get()
.cnode_child_attention_request_changed(self, false);
}
}
}
impl Debug for FloatNode {
@ -527,13 +553,16 @@ impl ContainingNode for FloatNode {
containing_node_impl!();
fn cnode_replace_child(self: Rc<Self>, _old: &dyn Node, new: Rc<dyn ToplevelNode>) {
self.discard_child_flags();
self.child.set(Some(new.clone()));
self.apply_child_flags();
new.tl_set_parent(self.clone());
new.clone().tl_set_workspace(&self.workspace.get());
self.schedule_layout();
}
fn cnode_remove_child2(self: Rc<Self>, _child: &dyn Node, _preserve_focus: bool) {
self.discard_child_flags();
self.child.set(None);
self.display_link.set(None);
self.workspace_link.set(None);
@ -542,6 +571,14 @@ impl ContainingNode for FloatNode {
fn cnode_accepts_child(&self, _node: &dyn Node) -> bool {
true
}
fn cnode_child_attention_request_changed(self: Rc<Self>, _node: &dyn Node, set: bool) {
if self.attention_requested.replace(set) != set {
self.workspace
.get()
.cnode_child_attention_request_changed(&*self, set);
}
}
}
impl StackedNode for FloatNode {

View file

@ -144,6 +144,7 @@ impl OutputNode {
let mut rd = self.render_data.borrow_mut();
rd.titles.clear();
rd.inactive_workspaces.clear();
rd.attention_requested_workspaces.clear();
rd.captured_inactive_workspaces.clear();
rd.active_workspace = None;
rd.status = None;
@ -219,10 +220,15 @@ impl OutputNode {
rect,
captured: ws.capture.get(),
});
} else if ws.capture.get() {
rd.captured_inactive_workspaces.push(rect);
} else {
rd.inactive_workspaces.push(rect);
if ws.attention_requests.active() {
rd.attention_requested_workspaces.push(rect);
}
if ws.capture.get() {
rd.captured_inactive_workspaces.push(rect);
} else {
rd.inactive_workspaces.push(rect);
}
}
pos += title_width;
}
@ -330,6 +336,7 @@ impl OutputNode {
jay_workspaces: Default::default(),
capture: self.state.default_workspace_capture.clone(),
title_texture: Default::default(),
attention_requests: Default::default(),
});
ws.output_link
.set(Some(self.workspaces.add_last(ws.clone())));
@ -493,6 +500,7 @@ pub struct OutputRenderData {
pub active_workspace: Option<OutputWorkspaceRenderData>,
pub underline: Rect,
pub inactive_workspaces: Vec<Rect>,
pub attention_requested_workspaces: Vec<Rect>,
pub captured_inactive_workspaces: Vec<Rect>,
pub titles: Vec<OutputTitle>,
pub status: Option<OutputStatus>,

View file

@ -5,7 +5,7 @@ use {
rect::Rect,
state::State,
tree::{ContainingNode, Direction, Node, OutputNode, PlaceholderNode, WorkspaceNode},
utils::{clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap},
utils::{clonecell::CloneCell, smallmap::SmallMap, threshold_counter::ThresholdCounter},
},
std::{
cell::{Cell, RefCell},
@ -42,14 +42,14 @@ pub trait ToplevelNode: Node {
fn tl_surface_active_changed(&self, active: bool) {
let data = self.tl_data();
if active {
if data.active_surfaces.fetch_add(1) == 0 {
if data.active_surfaces.inc() {
self.tl_set_active(true);
if let Some(parent) = data.parent.get() {
parent.node_child_active_changed(self.tl_as_node(), true, 1);
}
}
} else {
if data.active_surfaces.fetch_sub(1) == 1 {
if data.active_surfaces.dec() {
self.tl_set_active(false);
if let Some(parent) = data.parent.get() {
parent.node_child_active_changed(self.tl_as_node(), false, 1);
@ -109,7 +109,7 @@ pub trait ToplevelNode: Node {
_ => return,
};
let node = self.tl_as_node();
if data.active.get() || data.active_surfaces.get() > 0 {
if data.active.get() || data.active_surfaces.active() {
parent.clone().node_child_active_changed(node, true, 1);
}
}
@ -161,7 +161,7 @@ pub struct ToplevelData {
pub active: Cell<bool>,
pub client: Option<Rc<Client>>,
pub state: Rc<State>,
pub active_surfaces: NumCell<u32>,
pub active_surfaces: ThresholdCounter,
pub focus_node: SmallMap<SeatId, Rc<dyn Node>, 1>,
pub visible: Cell<bool>,
pub is_floating: Cell<bool>,
@ -174,6 +174,8 @@ pub struct ToplevelData {
pub parent: CloneCell<Option<Rc<dyn ContainingNode>>>,
pub pos: Cell<Rect>,
pub seat_state: NodeSeatState,
pub wants_attention: Cell<bool>,
pub requested_attention: Cell<bool>,
}
impl ToplevelData {
@ -195,6 +197,8 @@ impl ToplevelData {
parent: Default::default(),
pos: Default::default(),
seat_state: Default::default(),
wants_attention: Cell::new(false),
requested_attention: Cell::new(false),
}
}
@ -263,12 +267,10 @@ impl ToplevelData {
let mut kb_foci = Default::default();
if ws.visible.get() {
if let Some(container) = ws.container.get() {
kb_foci = collect_kb_foci(container.clone());
container.tl_set_visible(false);
kb_foci = collect_kb_foci(container);
}
for stacked in ws.stacked.iter() {
collect_kb_foci2(stacked.deref().clone().stacked_into_node(), &mut kb_foci);
stacked.stacked_set_visible(false);
}
}
*data = Some(FullscreenedData {
@ -277,7 +279,7 @@ impl ToplevelData {
});
drop(data);
self.is_fullscreen.set(true);
ws.fullscreen.set(Some(node.clone()));
ws.set_fullscreen_node(&node);
node.tl_set_parent(ws.clone());
node.clone().tl_set_workspace(ws);
node.clone()
@ -313,11 +315,7 @@ impl ToplevelData {
}
_ => {}
}
fd.workspace.fullscreen.take();
if node.node_visible() {
fd.workspace.set_visible(true);
fd.workspace.flush_jay_workspaces();
}
fd.workspace.remove_fullscreen_node();
if fd.placeholder.is_destroyed() {
state.map_tiled(node);
return;
@ -339,6 +337,31 @@ impl ToplevelData {
pub fn set_visible(&self, node: &dyn Node, visible: bool) {
self.visible.set(visible);
self.seat_state.set_visible(node, visible)
self.seat_state.set_visible(node, visible);
if !visible {
return;
}
if !self.requested_attention.replace(false) {
return;
}
self.wants_attention.set(false);
if let Some(parent) = self.parent.get() {
parent.cnode_child_attention_request_changed(node, false);
}
self.state.damage();
}
pub fn request_attention(&self, node: &dyn Node) {
if self.visible.get() {
return;
}
if self.requested_attention.replace(true) {
return;
}
self.wants_attention.set(true);
if let Some(parent) = self.parent.get() {
parent.cnode_child_attention_request_changed(node, true);
}
self.state.damage();
}
}

View file

@ -20,6 +20,7 @@ use {
clonecell::CloneCell,
copyhashmap::CopyHashMap,
linkedlist::{LinkedList, LinkedNode},
threshold_counter::ThresholdCounter,
},
wire::JayWorkspaceId,
},
@ -45,6 +46,7 @@ pub struct WorkspaceNode {
pub jay_workspaces: CopyHashMap<(ClientId, JayWorkspaceId), Rc<JayWorkspace>>,
pub capture: Cell<bool>,
pub title_texture: Cell<Option<TextTexture>>,
pub attention_requests: ThresholdCounter,
}
impl WorkspaceNode {
@ -74,6 +76,10 @@ impl WorkspaceNode {
}
pub fn set_container(self: &Rc<Self>, container: &Rc<ContainerNode>) {
if let Some(prev) = self.container.get() {
self.discard_child_flags(&*prev);
}
self.apply_child_flags(&**container);
let pos = self.position.get();
container.clone().tl_change_extents(&pos);
container.clone().tl_set_workspace(self);
@ -103,6 +109,15 @@ impl WorkspaceNode {
}
}
fn plane_set_visible(&self, visible: bool) {
if let Some(container) = self.container.get() {
container.tl_set_visible(visible);
}
for stacked in self.stacked.iter() {
stacked.stacked_set_visible(visible);
}
}
pub fn set_visible(&self, visible: bool) {
for jw in self.jay_workspaces.lock().values() {
jw.send_visible(visible);
@ -111,15 +126,52 @@ impl WorkspaceNode {
if let Some(fs) = self.fullscreen.get() {
fs.tl_set_visible(visible);
} else {
if let Some(container) = self.container.get() {
container.tl_set_visible(visible);
}
for stacked in self.stacked.iter() {
stacked.stacked_set_visible(visible);
}
self.plane_set_visible(visible);
}
self.seat_state.set_visible(self, visible);
}
pub fn set_fullscreen_node(&self, node: &Rc<dyn ToplevelNode>) {
let visible = self.visible.get();
let mut plane_was_visible = visible;
if let Some(prev) = self.fullscreen.set(Some(node.clone())) {
plane_was_visible = false;
self.discard_child_flags(&*prev);
}
self.apply_child_flags(&**node);
node.tl_set_visible(visible);
if plane_was_visible {
self.plane_set_visible(false);
}
}
pub fn remove_fullscreen_node(&self) {
if let Some(node) = self.fullscreen.take() {
self.discard_child_flags(&*node);
if self.visible.get() {
self.plane_set_visible(true);
}
}
}
fn apply_child_flags(&self, child: &dyn ToplevelNode) {
if child.tl_data().wants_attention.get() {
self.mod_attention_requested(true);
}
}
fn discard_child_flags(&self, child: &dyn ToplevelNode) {
if child.tl_data().wants_attention.get() {
self.mod_attention_requested(false);
}
}
fn mod_attention_requested(&self, set: bool) {
let crossed_threshold = self.attention_requests.adj(set);
if crossed_threshold {
self.output.get().schedule_update_render_data();
}
}
}
impl Node for WorkspaceNode {
@ -224,12 +276,14 @@ impl ContainingNode for WorkspaceNode {
fn cnode_remove_child2(self: Rc<Self>, child: &dyn Node, _preserve_focus: bool) {
if let Some(container) = self.container.get() {
if container.node_id() == child.node_id() {
self.discard_child_flags(&*container);
self.container.set(None);
return;
}
}
if let Some(fs) = self.fullscreen.get() {
if fs.tl_as_node().node_id() == child.node_id() {
self.discard_child_flags(&*fs);
self.fullscreen.set(None);
return;
}
@ -240,4 +294,8 @@ impl ContainingNode for WorkspaceNode {
fn cnode_accepts_child(&self, node: &dyn Node) -> bool {
node.node_is_container()
}
fn cnode_child_attention_request_changed(self: Rc<Self>, _node: &dyn Node, set: bool) {
self.mod_attention_requested(set);
}
}