tree: allow floats to be pinned
This commit is contained in:
parent
3e6640f0ca
commit
65a66c2e26
28 changed files with 528 additions and 36 deletions
|
|
@ -2041,6 +2041,14 @@ impl ContainingNode for ContainerNode {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cnode_pinned(&self) -> bool {
|
||||
self.tl_pinned()
|
||||
}
|
||||
|
||||
fn cnode_set_pinned(self: Rc<Self>, pinned: bool) {
|
||||
self.tl_set_pinned(false, pinned);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToplevelNodeBase for ContainerNode {
|
||||
|
|
|
|||
|
|
@ -31,4 +31,10 @@ pub trait ContainingNode: Node {
|
|||
let _ = new_y1;
|
||||
let _ = new_y2;
|
||||
}
|
||||
fn cnode_pinned(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn cnode_set_pinned(self: Rc<Self>, pinned: bool) {
|
||||
let _ = pinned;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use {
|
|||
cursor_user::CursorUser,
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::{
|
||||
BTN_LEFT, NodeSeatState, SeatId, WlSeatGlobal,
|
||||
BTN_LEFT, BTN_RIGHT, NodeSeatState, SeatId, WlSeatGlobal,
|
||||
tablet::{TabletTool, TabletToolChanges, TabletToolId},
|
||||
},
|
||||
rect::Rect,
|
||||
|
|
@ -15,7 +15,7 @@ use {
|
|||
text::TextTexture,
|
||||
tree::{
|
||||
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
|
||||
OutputNode, StackedNode, TileDragDestination, ToplevelNode, WorkspaceNode,
|
||||
OutputNode, PinnedNode, StackedNode, TileDragDestination, ToplevelNode, WorkspaceNode,
|
||||
walker::NodeVisitor,
|
||||
},
|
||||
utils::{
|
||||
|
|
@ -25,6 +25,7 @@ use {
|
|||
},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
arrayvec::ArrayVec,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
|
|
@ -42,6 +43,7 @@ pub struct FloatNode {
|
|||
pub position: Cell<Rect>,
|
||||
pub display_link: RefCell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||
pub workspace_link: Cell<Option<LinkedNode<Rc<dyn StackedNode>>>>,
|
||||
pub pinned_link: RefCell<Option<LinkedNode<Rc<dyn PinnedNode>>>>,
|
||||
pub workspace: CloneCell<Rc<WorkspaceNode>>,
|
||||
pub child: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||
pub active: Cell<bool>,
|
||||
|
|
@ -120,6 +122,7 @@ impl FloatNode {
|
|||
position: Cell::new(position),
|
||||
display_link: RefCell::new(None),
|
||||
workspace_link: Cell::new(None),
|
||||
pinned_link: RefCell::new(None),
|
||||
workspace: CloneCell::new(ws.clone()),
|
||||
child: CloneCell::new(Some(child.clone())),
|
||||
active: Cell::new(false),
|
||||
|
|
@ -144,6 +147,9 @@ impl FloatNode {
|
|||
if floater.visible.get() {
|
||||
state.damage(position);
|
||||
}
|
||||
if child.tl_data().pinned.get() {
|
||||
floater.toggle_pinned();
|
||||
}
|
||||
floater
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +223,9 @@ impl FloatNode {
|
|||
let mut th = tr.height();
|
||||
let mut scalef = None;
|
||||
let mut width = tr.width();
|
||||
if self.state.show_pin_icon.get() || self.pinned_link.borrow().is_some() {
|
||||
width = (width - th).max(0);
|
||||
}
|
||||
if *scale != 1 {
|
||||
let scale = scale.to_f64();
|
||||
th = (th as f64 * scale).round() as _;
|
||||
|
|
@ -402,17 +411,32 @@ impl FloatNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_workspace(self: &Rc<Self>, ws: &Rc<WorkspaceNode>) {
|
||||
fn set_workspace_(
|
||||
self: &Rc<Self>,
|
||||
ws: &Rc<WorkspaceNode>,
|
||||
update_pinned: bool,
|
||||
update_visible: bool,
|
||||
) {
|
||||
if let Some(c) = self.child.get() {
|
||||
c.tl_set_workspace(ws);
|
||||
}
|
||||
self.workspace_link
|
||||
.set(Some(ws.stacked.add_last(self.clone())));
|
||||
self.workspace.set(ws.clone());
|
||||
self.stacked_set_visible(ws.float_visible());
|
||||
if update_visible {
|
||||
self.stacked_set_visible(ws.float_visible());
|
||||
}
|
||||
if update_pinned {
|
||||
if let Some(pl) = &*self.pinned_link.borrow_mut() {
|
||||
ws.output.get().pinned.add_last_existing(pl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_position_after_ws_move(self: &Rc<Self>, output: &Rc<OutputNode>) {
|
||||
pub fn after_ws_move(self: &Rc<Self>, output: &Rc<OutputNode>) {
|
||||
if let Some(pinned) = &*self.pinned_link.borrow() {
|
||||
output.pinned.add_last_existing(pinned);
|
||||
}
|
||||
if output.is_dummy {
|
||||
return;
|
||||
}
|
||||
|
|
@ -505,6 +529,20 @@ impl FloatNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn toggle_pinned(self: &Rc<Self>) {
|
||||
let pl = &mut *self.pinned_link.borrow_mut();
|
||||
*pl = if pl.is_some() {
|
||||
None
|
||||
} else {
|
||||
let output = self.workspace.get().output.get();
|
||||
Some(output.pinned.add_last(self.clone()))
|
||||
};
|
||||
if let Some(tl) = self.child.get() {
|
||||
tl.tl_data().pinned.set(pl.is_some());
|
||||
}
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
|
||||
fn button(
|
||||
self: Rc<Self>,
|
||||
id: CursorType,
|
||||
|
|
@ -518,6 +556,34 @@ impl FloatNode {
|
|||
Some(s) => s,
|
||||
_ => return,
|
||||
};
|
||||
let bw = self.state.theme.sizes.border_width.get();
|
||||
let th = self.state.theme.sizes.title_height.get();
|
||||
let mut is_icon_press = false;
|
||||
if pressed && cursor_data.x >= bw && cursor_data.y >= bw && cursor_data.y < bw + th {
|
||||
enum FloatIcon {
|
||||
Pin,
|
||||
}
|
||||
let mut icons = ArrayVec::<FloatIcon, 1>::new();
|
||||
if self.state.show_pin_icon.get() || self.pinned_link.borrow().is_some() {
|
||||
icons.push(FloatIcon::Pin);
|
||||
}
|
||||
let mut x2 = bw + th;
|
||||
let icon = 'icon: {
|
||||
for icon in icons {
|
||||
if cursor_data.x < x2 {
|
||||
break 'icon Some(icon);
|
||||
}
|
||||
x2 += th;
|
||||
}
|
||||
None
|
||||
};
|
||||
if let Some(icon) = icon {
|
||||
is_icon_press = true;
|
||||
match icon {
|
||||
FloatIcon::Pin => self.toggle_pinned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
if !cursor_data.op_active {
|
||||
if !pressed {
|
||||
return;
|
||||
|
|
@ -533,6 +599,7 @@ impl FloatNode {
|
|||
cursor_data.x,
|
||||
cursor_data.y,
|
||||
) && cursor_data.op_type == OpType::Move
|
||||
&& !is_icon_press
|
||||
{
|
||||
if let Some(tl) = self.child.get() {
|
||||
drop(cursors);
|
||||
|
|
@ -572,7 +639,7 @@ impl FloatNode {
|
|||
} else if !pressed {
|
||||
cursor_data.op_active = false;
|
||||
let ws = cursor.output().ensure_workspace();
|
||||
self.set_workspace(&ws);
|
||||
self.set_workspace_(&ws, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -681,6 +748,9 @@ impl Node for FloatNode {
|
|||
state: KeyState,
|
||||
_serial: u64,
|
||||
) {
|
||||
if button == BTN_RIGHT && state == KeyState::Pressed {
|
||||
self.toggle_pinned();
|
||||
}
|
||||
if button != BTN_LEFT {
|
||||
return;
|
||||
}
|
||||
|
|
@ -800,6 +870,7 @@ impl ContainingNode for FloatNode {
|
|||
self.child.set(None);
|
||||
self.display_link.borrow_mut().take();
|
||||
self.workspace_link.set(None);
|
||||
self.pinned_link.take();
|
||||
if self.visible.get() {
|
||||
self.state.damage(self.position.get());
|
||||
}
|
||||
|
|
@ -874,6 +945,17 @@ impl ContainingNode for FloatNode {
|
|||
self.schedule_layout();
|
||||
}
|
||||
}
|
||||
|
||||
fn cnode_pinned(&self) -> bool {
|
||||
self.pinned_link.borrow().is_some()
|
||||
}
|
||||
|
||||
fn cnode_set_pinned(self: Rc<Self>, pinned: bool) {
|
||||
if self.pinned_link.borrow().is_some() == pinned {
|
||||
return;
|
||||
}
|
||||
self.toggle_pinned();
|
||||
}
|
||||
}
|
||||
|
||||
impl StackedNode for FloatNode {
|
||||
|
|
@ -891,3 +973,9 @@ impl StackedNode for FloatNode {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl PinnedNode for FloatNode {
|
||||
fn set_workspace(self: Rc<Self>, workspace: &Rc<WorkspaceNode>, update_visible: bool) {
|
||||
self.set_workspace_(workspace, false, update_visible);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ use {
|
|||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, StackedNode,
|
||||
TddType, TileDragDestination, WorkspaceDragDestination, WorkspaceNode, WorkspaceNodeId,
|
||||
walker::NodeVisitor,
|
||||
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, PinnedNode,
|
||||
StackedNode, TddType, TileDragDestination, WorkspaceDragDestination, WorkspaceNode,
|
||||
WorkspaceNodeId, walker::NodeVisitor,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||
|
|
@ -103,6 +103,7 @@ pub struct OutputNode {
|
|||
pub tray_start_rel: Cell<i32>,
|
||||
pub tray_items: LinkedList<Rc<dyn DynTrayItem>>,
|
||||
pub ext_workspace_groups: CopyHashMap<WorkspaceManagerId, Rc<ExtWorkspaceGroupHandleV1>>,
|
||||
pub pinned: LinkedList<Rc<dyn PinnedNode>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
|
|
@ -646,6 +647,9 @@ impl OutputNode {
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use crate::tree::Node;
|
||||
use {
|
||||
crate::tree::{Node, WorkspaceNode},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub trait StackedNode: Node {
|
||||
fn stacked_prepare_set_visible(&self) {
|
||||
|
|
@ -14,3 +17,7 @@ pub trait StackedNode: Node {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PinnedNode: StackedNode {
|
||||
fn set_workspace(self: Rc<Self>, workspace: &Rc<WorkspaceNode>, update_visible: bool);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ pub trait ToplevelNode: ToplevelNodeBase {
|
|||
fn tl_change_extents(self: Rc<Self>, rect: &Rect);
|
||||
fn tl_set_visible(&self, visible: bool);
|
||||
fn tl_destroy(&self);
|
||||
fn tl_pinned(&self) -> bool;
|
||||
fn tl_set_pinned(&self, self_pinned: bool, pinned: bool);
|
||||
}
|
||||
|
||||
impl<T: ToplevelNodeBase> ToplevelNode for T {
|
||||
|
|
@ -151,6 +153,24 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
|
|||
self.tl_data().destroy_node(self);
|
||||
self.tl_destroy_impl();
|
||||
}
|
||||
|
||||
fn tl_pinned(&self) -> bool {
|
||||
let Some(parent) = self.tl_data().parent.get() else {
|
||||
return false;
|
||||
};
|
||||
parent.cnode_pinned()
|
||||
}
|
||||
|
||||
fn tl_set_pinned(&self, self_pinned: bool, pinned: bool) {
|
||||
let data = self.tl_data();
|
||||
if self_pinned {
|
||||
data.pinned.set(pinned);
|
||||
}
|
||||
let Some(parent) = data.parent.get() else {
|
||||
return;
|
||||
};
|
||||
parent.cnode_set_pinned(pinned);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToplevelNodeBase: Node {
|
||||
|
|
@ -243,6 +263,7 @@ pub struct ToplevelData {
|
|||
pub is_floating: Cell<bool>,
|
||||
pub float_width: Cell<i32>,
|
||||
pub float_height: Cell<i32>,
|
||||
pub pinned: Cell<bool>,
|
||||
pub is_fullscreen: Cell<bool>,
|
||||
pub fullscrceen_data: RefCell<Option<FullscreenedData>>,
|
||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||
|
|
@ -283,6 +304,7 @@ impl ToplevelData {
|
|||
is_floating: Default::default(),
|
||||
float_width: Default::default(),
|
||||
float_height: Default::default(),
|
||||
pinned: Cell::new(false),
|
||||
is_fullscreen: Default::default(),
|
||||
fullscrceen_data: Default::default(),
|
||||
workspace: Default::default(),
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ impl WorkspaceNode {
|
|||
}
|
||||
|
||||
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||
node.adjust_position_after_ws_move(self.0);
|
||||
node.after_ws_move(self.0);
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
|
||||
|
|
@ -426,6 +426,27 @@ pub fn move_ws_to_output(
|
|||
config: WsMoveConfig,
|
||||
) {
|
||||
let source = ws.output.get();
|
||||
if let Some(visible) = source.workspace.get() {
|
||||
if visible.id == ws.id {
|
||||
source.workspace.take();
|
||||
}
|
||||
}
|
||||
let mut new_source_ws = None;
|
||||
if !config.source_is_destroyed && !source.is_dummy && source.workspace.is_none() {
|
||||
new_source_ws = source
|
||||
.workspaces
|
||||
.iter()
|
||||
.find(|c| c.id != ws.id)
|
||||
.map(|c| (*c).clone());
|
||||
if new_source_ws.is_none() && source.pinned.is_not_empty() {
|
||||
new_source_ws = Some(source.generate_workspace());
|
||||
}
|
||||
}
|
||||
if let Some(new_source_ws) = &new_source_ws {
|
||||
for pinned in source.pinned.iter() {
|
||||
pinned.deref().clone().set_workspace(new_source_ws, false);
|
||||
}
|
||||
}
|
||||
ws.set_output(&target);
|
||||
'link: {
|
||||
if let Some(before) = config.before {
|
||||
|
|
@ -445,18 +466,9 @@ pub fn move_ws_to_output(
|
|||
ws.set_visible(false);
|
||||
}
|
||||
ws.flush_jay_workspaces();
|
||||
if let Some(visible) = source.workspace.get() {
|
||||
if visible.id == ws.id {
|
||||
source.workspace.take();
|
||||
}
|
||||
}
|
||||
if !config.source_is_destroyed && !source.is_dummy {
|
||||
if source.workspace.is_none() {
|
||||
if let Some(ws) = source.workspaces.first() {
|
||||
source.show_workspace(&ws);
|
||||
ws.flush_jay_workspaces();
|
||||
}
|
||||
}
|
||||
if let Some(ws) = new_source_ws {
|
||||
source.show_workspace(&ws);
|
||||
ws.flush_jay_workspaces();
|
||||
}
|
||||
if !target.is_dummy {
|
||||
target.schedule_update_render_data();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue