1
0
Fork 0
forked from wry/wry

tree: split output workspaces

This commit is contained in:
kossLAN 2026-05-29 21:46:18 -04:00
parent 112b1a8e5f
commit fa1ad20864
No known key found for this signature in database
2 changed files with 128 additions and 115 deletions

View file

@ -1,5 +1,6 @@
mod policy;
mod render_data;
mod workspaces;
#[allow(unused_imports)]
pub use {
@ -27,7 +28,7 @@ use {
wl_buffer::WlBufferStorage,
wl_output::{BlendSpace, WlOutputGlobal},
wl_seat::{
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci2,
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal,
tablet::{TabletTool, TabletToolChanges, TabletToolId},
wl_pointer::PendingScroll,
},
@ -69,7 +70,7 @@ use {
errorfmt::ErrorFmt,
event_listener::{EventSource, LazyEventSource},
hash_map_ext::HashMapExt,
linkedlist::{LinkedList, NodeRef},
linkedlist::LinkedList,
on_drop_event::OnDropEvent,
scroller::Scroller,
},
@ -77,9 +78,7 @@ use {
ExtImageCopyCaptureSessionV1Id, JayOutputId, ZwlrScreencopyFrameV1Id,
},
},
ahash::AHashMap,
numeric_sort::cmp,
smallvec::SmallVec,
std::{
cell::{Cell, RefCell},
fmt::{Debug, Formatter},
@ -648,117 +647,6 @@ impl OutputNode {
}
}
pub fn ensure_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
if let Some(ws) = self.workspace.get() {
if !ws.is_dummy {
return ws;
}
}
self.generate_workspace()
}
pub fn generate_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
let name = 'name: {
for i in 1.. {
let name = i.to_string();
if self.find_workspace(&name).is_none() {
break 'name name;
}
}
unreachable!();
};
self.create_workspace(&name)
}
pub fn find_workspace(&self, name: &str) -> Option<Rc<WorkspaceNode>> {
self.workspaces
.iter()
.find(|ws| ws.name.as_str() == name)
.map(|ws| (*ws).clone())
}
pub fn show_workspace(&self, ws: &Rc<WorkspaceNode>) -> bool {
let mut seats = SmallVec::new();
if let Some(old) = self.workspace.set(Some(ws.clone())) {
if old.id == ws.id {
return false;
}
collect_kb_foci2(old.clone(), &mut seats);
for pinned in self.pinned.iter() {
pinned.deref().clone().set_workspace(ws, false);
}
if old.is_empty() {
for jw in old.jay_workspaces.lock().values() {
jw.send_destroyed();
jw.workspace.set(None);
}
for wh in old.ext_workspaces.lock().values() {
wh.handle_destroyed();
}
old.clear();
self.state.workspaces.remove(&old.id);
} else {
old.set_visible(false);
old.flush_jay_workspaces();
}
}
self.update_visible();
self.update_presentation_type();
if let Some(fs) = ws.fullscreen.get() {
fs.tl_change_extents(&self.global.pos.get());
}
ws.change_extents(&self.workspace_rect.get());
for seat in seats {
ws.clone().node_do_focus(&seat, Direction::Unspecified);
}
if self.node_visible() {
self.state.damage(self.global.pos.get());
}
true
}
pub fn find_workspace_insertion_point(&self, name: &str) -> Option<NodeRef<Rc<WorkspaceNode>>> {
if self.state.workspace_display_order.get() == WorkspaceDisplayOrder::Sorted {
for existing_ws in self.workspaces.iter() {
if cmp(name, &existing_ws.name) == std::cmp::Ordering::Less {
return Some(existing_ws);
}
}
}
None
}
pub fn create_workspace(self: &Rc<Self>, name: &str) -> Rc<WorkspaceNode> {
let ws = WorkspaceNode::new(self, name, false);
ws.opt.set(Some(ws.clone()));
ws.update_has_captures();
let link = if let Some(before) = self.find_workspace_insertion_point(name) {
before.prepend(ws.clone())
} else {
self.workspaces.add_last(ws.clone())
};
*ws.output_link.borrow_mut() = Some(link);
self.state.workspaces.set(ws.id, ws.clone());
if self.workspace.is_none() {
self.show_workspace(&ws);
}
let mut clients_to_kill = AHashMap::new();
for watcher in self.state.workspace_watchers.lock().values() {
if let Err(e) = watcher.send_workspace(&ws) {
clients_to_kill.insert(watcher.client.id, (watcher.client.clone(), e));
}
}
for (client, e) in clients_to_kill.values() {
client.error(e);
}
self.state.workspace_managers.announce_workspace(self, &ws);
self.state
.workspace_managers
.update_workspace_coordinates(self);
self.schedule_update_render_data();
ws
}
pub fn update_rects(self: &Rc<Self>) {
let rect = self.global.pos.get();
let bh = self.state.theme.sizes.bar_height();

View file

@ -0,0 +1,125 @@
use {
super::OutputNode,
crate::{
ifs::wl_seat::collect_kb_foci2,
tree::{Direction, Node, WorkspaceDisplayOrder, WorkspaceNode},
utils::linkedlist::NodeRef,
},
ahash::AHashMap,
numeric_sort::cmp,
smallvec::SmallVec,
std::{ops::Deref, rc::Rc},
};
impl OutputNode {
pub fn ensure_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
if let Some(ws) = self.workspace.get() {
if !ws.is_dummy {
return ws;
}
}
self.generate_workspace()
}
pub fn generate_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
let name = 'name: {
for i in 1.. {
let name = i.to_string();
if self.find_workspace(&name).is_none() {
break 'name name;
}
}
unreachable!();
};
self.create_workspace(&name)
}
pub fn find_workspace(&self, name: &str) -> Option<Rc<WorkspaceNode>> {
self.workspaces
.iter()
.find(|ws| ws.name.as_str() == name)
.map(|ws| (*ws).clone())
}
pub fn show_workspace(&self, ws: &Rc<WorkspaceNode>) -> bool {
let mut seats = SmallVec::new();
if let Some(old) = self.workspace.set(Some(ws.clone())) {
if old.id == ws.id {
return false;
}
collect_kb_foci2(old.clone(), &mut seats);
for pinned in self.pinned.iter() {
pinned.deref().clone().set_workspace(ws, false);
}
if old.is_empty() {
for jw in old.jay_workspaces.lock().values() {
jw.send_destroyed();
jw.workspace.set(None);
}
for wh in old.ext_workspaces.lock().values() {
wh.handle_destroyed();
}
old.clear();
self.state.workspaces.remove(&old.id);
} else {
old.set_visible(false);
old.flush_jay_workspaces();
}
}
self.update_visible();
self.update_presentation_type();
if let Some(fs) = ws.fullscreen.get() {
fs.tl_change_extents(&self.global.pos.get());
}
ws.change_extents(&self.workspace_rect.get());
for seat in seats {
ws.clone().node_do_focus(&seat, Direction::Unspecified);
}
if self.node_visible() {
self.state.damage(self.global.pos.get());
}
true
}
pub fn find_workspace_insertion_point(&self, name: &str) -> Option<NodeRef<Rc<WorkspaceNode>>> {
if self.state.workspace_display_order.get() == WorkspaceDisplayOrder::Sorted {
for existing_ws in self.workspaces.iter() {
if cmp(name, &existing_ws.name) == std::cmp::Ordering::Less {
return Some(existing_ws);
}
}
}
None
}
pub fn create_workspace(self: &Rc<Self>, name: &str) -> Rc<WorkspaceNode> {
let ws = WorkspaceNode::new(self, name, false);
ws.opt.set(Some(ws.clone()));
ws.update_has_captures();
let link = if let Some(before) = self.find_workspace_insertion_point(name) {
before.prepend(ws.clone())
} else {
self.workspaces.add_last(ws.clone())
};
*ws.output_link.borrow_mut() = Some(link);
self.state.workspaces.set(ws.id, ws.clone());
if self.workspace.is_none() {
self.show_workspace(&ws);
}
let mut clients_to_kill = AHashMap::new();
for watcher in self.state.workspace_watchers.lock().values() {
if let Err(e) = watcher.send_workspace(&ws) {
clients_to_kill.insert(watcher.client.id, (watcher.client.clone(), e));
}
}
for (client, e) in clients_to_kill.values() {
client.error(e);
}
self.state.workspace_managers.announce_workspace(self, &ws);
self.state
.workspace_managers
.update_workspace_coordinates(self);
self.schedule_update_render_data();
ws
}
}