tree: split output workspaces
This commit is contained in:
parent
112b1a8e5f
commit
fa1ad20864
2 changed files with 128 additions and 115 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
mod policy;
|
mod policy;
|
||||||
mod render_data;
|
mod render_data;
|
||||||
|
mod workspaces;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub use {
|
pub use {
|
||||||
|
|
@ -27,7 +28,7 @@ use {
|
||||||
wl_buffer::WlBufferStorage,
|
wl_buffer::WlBufferStorage,
|
||||||
wl_output::{BlendSpace, WlOutputGlobal},
|
wl_output::{BlendSpace, WlOutputGlobal},
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal, collect_kb_foci2,
|
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal,
|
||||||
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
||||||
wl_pointer::PendingScroll,
|
wl_pointer::PendingScroll,
|
||||||
},
|
},
|
||||||
|
|
@ -69,7 +70,7 @@ use {
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
event_listener::{EventSource, LazyEventSource},
|
event_listener::{EventSource, LazyEventSource},
|
||||||
hash_map_ext::HashMapExt,
|
hash_map_ext::HashMapExt,
|
||||||
linkedlist::{LinkedList, NodeRef},
|
linkedlist::LinkedList,
|
||||||
on_drop_event::OnDropEvent,
|
on_drop_event::OnDropEvent,
|
||||||
scroller::Scroller,
|
scroller::Scroller,
|
||||||
},
|
},
|
||||||
|
|
@ -77,9 +78,7 @@ use {
|
||||||
ExtImageCopyCaptureSessionV1Id, JayOutputId, ZwlrScreencopyFrameV1Id,
|
ExtImageCopyCaptureSessionV1Id, JayOutputId, ZwlrScreencopyFrameV1Id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
|
||||||
numeric_sort::cmp,
|
numeric_sort::cmp,
|
||||||
smallvec::SmallVec,
|
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Formatter},
|
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>) {
|
pub fn update_rects(self: &Rc<Self>) {
|
||||||
let rect = self.global.pos.get();
|
let rect = self.global.pos.get();
|
||||||
let bh = self.state.theme.sizes.bar_height();
|
let bh = self.state.theme.sizes.bar_height();
|
||||||
|
|
|
||||||
125
src/tree/output/workspaces.rs
Normal file
125
src/tree/output/workspaces.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue