all: remove traditional i3 titlebars, add corner rounding
This commit is contained in:
parent
e1928863d9
commit
a41dbae899
52 changed files with 1866 additions and 1047 deletions
|
|
@ -10,27 +10,22 @@ use {
|
|||
},
|
||||
rect::Rect,
|
||||
renderer::Renderer,
|
||||
scale::Scale,
|
||||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
|
||||
NodeLayerLink, NodeLocation, OutputNode, PinnedNode, StackedNode, TileDragDestination,
|
||||
ToplevelNode, WorkspaceNode, toplevel_set_floating, walker::NodeVisitor,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, clonecell::CloneCell, double_click_state::DoubleClickState,
|
||||
errorfmt::ErrorFmt, event_listener::LazyEventSource, linkedlist::LinkedNode,
|
||||
on_drop_event::OnDropEvent, smallmap::SmallMapMut,
|
||||
clonecell::CloneCell, double_click_state::DoubleClickState,
|
||||
event_listener::LazyEventSource, linkedlist::LinkedNode,
|
||||
},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
arrayvec::ArrayVec,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
mem,
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
},
|
||||
};
|
||||
|
|
@ -50,10 +45,6 @@ pub struct FloatNode {
|
|||
pub active: Cell<bool>,
|
||||
pub seat_state: NodeSeatState,
|
||||
pub layout_scheduled: Cell<bool>,
|
||||
pub render_titles_scheduled: Cell<bool>,
|
||||
pub title_rect: Cell<Rect>,
|
||||
pub title: RefCell<String>,
|
||||
pub title_textures: RefCell<SmallMapMut<Scale, TextTexture, 2>>,
|
||||
cursors: RefCell<AHashMap<CursorType, CursorState>>,
|
||||
pub attention_requested: Cell<bool>,
|
||||
pub layout_complete: Rc<LazyEventSource>,
|
||||
|
|
@ -99,17 +90,6 @@ pub async fn float_layout(state: Rc<State>) {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn float_titles(state: Rc<State>) {
|
||||
loop {
|
||||
let node = state.pending_float_titles.pop().await;
|
||||
if node.render_titles_scheduled.get() {
|
||||
node.render_titles_scheduled.set(false);
|
||||
node.render_title_phase1().triggered().await;
|
||||
node.render_title_phase2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatNode {
|
||||
pub fn new(
|
||||
state: &Rc<State>,
|
||||
|
|
@ -131,10 +111,6 @@ impl FloatNode {
|
|||
active: Cell::new(false),
|
||||
seat_state: Default::default(),
|
||||
layout_scheduled: Cell::new(false),
|
||||
render_titles_scheduled: Cell::new(false),
|
||||
title_rect: Default::default(),
|
||||
title: Default::default(),
|
||||
title_textures: Default::default(),
|
||||
cursors: Default::default(),
|
||||
attention_requested: Cell::new(false),
|
||||
layout_complete: state.post_layout_event_sources.create_source(),
|
||||
|
|
@ -162,7 +138,7 @@ impl FloatNode {
|
|||
}
|
||||
|
||||
pub fn on_colors_changed(self: &Rc<Self>) {
|
||||
self.schedule_render_titles();
|
||||
// No title rendering needed
|
||||
}
|
||||
|
||||
pub fn schedule_layout(self: &Rc<Self>) {
|
||||
|
|
@ -179,95 +155,17 @@ impl FloatNode {
|
|||
let pos = self.position.get();
|
||||
let theme = &self.state.theme;
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let th = theme.title_height();
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let cpos = Rect::new_sized_saturating(
|
||||
pos.x1() + bw,
|
||||
pos.y1() + bw + tpuh,
|
||||
pos.y1() + bw,
|
||||
pos.width() - 2 * bw,
|
||||
pos.height() - 2 * bw - tpuh,
|
||||
pos.height() - 2 * bw,
|
||||
);
|
||||
let tr = Rect::new_sized_saturating(bw, bw, pos.width() - 2 * bw, th);
|
||||
child.clone().tl_change_extents(&cpos);
|
||||
self.title_rect.set(tr);
|
||||
self.layout_scheduled.set(false);
|
||||
self.schedule_render_titles();
|
||||
self.layout_complete.trigger();
|
||||
}
|
||||
|
||||
pub fn schedule_render_titles(self: &Rc<Self>) {
|
||||
if !self.render_titles_scheduled.replace(true) {
|
||||
self.state.pending_float_titles.push(self.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn render_title_phase1(&self) -> Rc<AsyncEvent> {
|
||||
let on_completed = Rc::new(OnDropEvent::default());
|
||||
let theme = &self.state.theme;
|
||||
let tc = match self.active.get() {
|
||||
true => theme.colors.focused_title_text.get(),
|
||||
false => theme.colors.unfocused_title_text.get(),
|
||||
};
|
||||
let font = theme.title_font();
|
||||
let title = self.title.borrow_mut();
|
||||
let ctx = match self.state.render_ctx.get() {
|
||||
Some(c) => c,
|
||||
_ => return on_completed.event(),
|
||||
};
|
||||
let scales = self.state.scales.lock();
|
||||
let tr = self.title_rect.get();
|
||||
let tt = &mut *self.title_textures.borrow_mut();
|
||||
for (scale, _) in scales.iter() {
|
||||
let tex = tt.get_or_insert_with(*scale, || TextTexture::new(&self.state, &ctx));
|
||||
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 _;
|
||||
width = (width as f64 * scale).round() as _;
|
||||
scalef = Some(scale);
|
||||
}
|
||||
tex.schedule_render(
|
||||
on_completed.clone(),
|
||||
1,
|
||||
None,
|
||||
width,
|
||||
th,
|
||||
1,
|
||||
&font,
|
||||
&title,
|
||||
tc,
|
||||
true,
|
||||
false,
|
||||
scalef,
|
||||
);
|
||||
}
|
||||
on_completed.event()
|
||||
}
|
||||
|
||||
fn render_title_phase2(&self) {
|
||||
let theme = &self.state.theme;
|
||||
let th = theme.title_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let title = self.title.borrow();
|
||||
let tt = &*self.title_textures.borrow();
|
||||
for (_, tt) in tt {
|
||||
if let Err(e) = tt.flip() {
|
||||
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
let pos = self.position.get();
|
||||
if self.visible.get() && pos.width() >= 2 * bw {
|
||||
let tr =
|
||||
Rect::new_sized_saturating(pos.x1() + bw, pos.y1() + bw, pos.width() - 2 * bw, th);
|
||||
self.state.damage(tr);
|
||||
}
|
||||
}
|
||||
|
||||
fn pointer_move(
|
||||
self: &Rc<Self>,
|
||||
id: CursorType,
|
||||
|
|
@ -280,7 +178,6 @@ impl FloatNode {
|
|||
let y = y.round_down();
|
||||
let theme = &self.state.theme;
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let mut seats = self.cursors.borrow_mut();
|
||||
let seat_state = seats.entry(id).or_insert_with(|| CursorState {
|
||||
cursor: KnownCursor::Default,
|
||||
|
|
@ -316,7 +213,7 @@ impl FloatNode {
|
|||
}
|
||||
OpType::ResizeTop => {
|
||||
y1 += y - seat_state.dist_ver;
|
||||
y1 = y1.min(y2 - 2 * bw - tpuh);
|
||||
y1 = y1.min(y2 - 2 * bw);
|
||||
}
|
||||
OpType::ResizeRight => {
|
||||
x2 += x - pos.width() + seat_state.dist_hor;
|
||||
|
|
@ -324,31 +221,31 @@ impl FloatNode {
|
|||
}
|
||||
OpType::ResizeBottom => {
|
||||
y2 += y - pos.height() + seat_state.dist_ver;
|
||||
y2 = y2.max(y1 + 2 * bw + tpuh);
|
||||
y2 = y2.max(y1 + 2 * bw);
|
||||
}
|
||||
OpType::ResizeTopLeft => {
|
||||
x1 += x - seat_state.dist_hor;
|
||||
y1 += y - seat_state.dist_ver;
|
||||
x1 = x1.min(x2 - 2 * bw);
|
||||
y1 = y1.min(y2 - 2 * bw - tpuh);
|
||||
y1 = y1.min(y2 - 2 * bw);
|
||||
}
|
||||
OpType::ResizeTopRight => {
|
||||
x2 += x - pos.width() + seat_state.dist_hor;
|
||||
y1 += y - seat_state.dist_ver;
|
||||
x2 = x2.max(x1 + 2 * bw);
|
||||
y1 = y1.min(y2 - 2 * bw - tpuh);
|
||||
y1 = y1.min(y2 - 2 * bw);
|
||||
}
|
||||
OpType::ResizeBottomLeft => {
|
||||
x1 += x - seat_state.dist_hor;
|
||||
y2 += y - pos.height() + seat_state.dist_ver;
|
||||
x1 = x1.min(x2 - 2 * bw);
|
||||
y2 = y2.max(y1 + 2 * bw + tpuh);
|
||||
y2 = y2.max(y1 + 2 * bw);
|
||||
}
|
||||
OpType::ResizeBottomRight => {
|
||||
x2 += x - pos.width() + seat_state.dist_hor;
|
||||
y2 += y - pos.height() + seat_state.dist_ver;
|
||||
x2 = x2.max(x1 + 2 * bw);
|
||||
y2 = y2.max(y1 + 2 * bw + tpuh);
|
||||
y2 = y2.max(y1 + 2 * bw);
|
||||
}
|
||||
}
|
||||
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
|
||||
|
|
@ -474,18 +371,12 @@ impl FloatNode {
|
|||
self.schedule_layout();
|
||||
}
|
||||
|
||||
fn update_child_title(self: &Rc<Self>, title: &str) {
|
||||
let mut t = self.title.borrow_mut();
|
||||
if t.deref() != title {
|
||||
t.clear();
|
||||
t.push_str(title);
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
fn update_child_title(self: &Rc<Self>, _title: &str) {
|
||||
// No title rendering
|
||||
}
|
||||
|
||||
fn update_child_active(self: &Rc<Self>, active: bool) {
|
||||
if self.active.replace(active) != active {
|
||||
self.schedule_render_titles();
|
||||
if active {
|
||||
self.restack();
|
||||
}
|
||||
|
|
@ -542,7 +433,6 @@ impl FloatNode {
|
|||
if let Some(tl) = self.child.get() {
|
||||
tl.tl_data().pinned.set(pl.is_some());
|
||||
}
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
|
||||
fn button(
|
||||
|
|
@ -558,34 +448,6 @@ impl FloatNode {
|
|||
Some(s) => s,
|
||||
_ => return,
|
||||
};
|
||||
let bw = self.state.theme.sizes.border_width.get();
|
||||
let th = self.state.theme.title_height();
|
||||
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;
|
||||
|
|
@ -601,7 +463,6 @@ impl FloatNode {
|
|||
cursor_data.x,
|
||||
cursor_data.y,
|
||||
) && cursor_data.op_type == OpType::Move
|
||||
&& !is_icon_press
|
||||
&& let Some(tl) = self.child.get()
|
||||
{
|
||||
drop(cursors);
|
||||
|
|
@ -653,11 +514,10 @@ impl FloatNode {
|
|||
let child = self.child.get()?;
|
||||
let theme = &self.state.theme.sizes;
|
||||
let bw = theme.border_width.get();
|
||||
let tpuh = self.state.theme.title_plus_underline_height();
|
||||
let pos = self.position.get();
|
||||
let body = Rect::new(
|
||||
pos.x1() + bw,
|
||||
pos.y1() + bw + tpuh,
|
||||
pos.y1() + bw,
|
||||
pos.x2() - bw,
|
||||
pos.y2() - bw,
|
||||
)?;
|
||||
|
|
@ -713,8 +573,8 @@ impl Node for FloatNode {
|
|||
NodeLayerLink::Stacked(l)
|
||||
}
|
||||
|
||||
fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, title: &str) {
|
||||
self.update_child_title(title);
|
||||
fn node_child_title_changed(self: Rc<Self>, _child: &dyn Node, _title: &str) {
|
||||
// No title rendering
|
||||
}
|
||||
|
||||
fn node_accepts_focus(&self) -> bool {
|
||||
|
|
@ -738,13 +598,12 @@ impl Node for FloatNode {
|
|||
usecase: FindTreeUsecase,
|
||||
) -> FindTreeResult {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let pos = self.position.get();
|
||||
if x < bw || x >= pos.width() - bw {
|
||||
return FindTreeResult::AcceptsInput;
|
||||
}
|
||||
if y < bw + tpuh || y >= pos.height() - bw {
|
||||
if y < bw || y >= pos.height() - bw {
|
||||
return FindTreeResult::AcceptsInput;
|
||||
}
|
||||
let child = match self.child.get() {
|
||||
|
|
@ -752,7 +611,7 @@ impl Node for FloatNode {
|
|||
_ => return FindTreeResult::Other,
|
||||
};
|
||||
let x = x - bw;
|
||||
let y = y - bw - tpuh;
|
||||
let y = y - bw;
|
||||
tree.push(FoundNode {
|
||||
node: child.clone(),
|
||||
x,
|
||||
|
|
@ -934,9 +793,8 @@ impl ContainingNode for FloatNode {
|
|||
|
||||
fn cnode_set_child_position(self: Rc<Self>, _child: &dyn Node, x: i32, y: i32) {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let (x, y) = (x - bw, y - tpuh - bw);
|
||||
let (x, y) = (x - bw, y - bw);
|
||||
let pos = self.position.get();
|
||||
if pos.position() != (x, y) {
|
||||
let new_pos = pos.at_point(x, y);
|
||||
|
|
@ -956,7 +814,6 @@ impl ContainingNode for FloatNode {
|
|||
new_y2: Option<i32>,
|
||||
) {
|
||||
let theme = &self.state.theme;
|
||||
let tpuh = theme.title_plus_underline_height();
|
||||
let bw = theme.sizes.border_width.get();
|
||||
let pos = self.position.get();
|
||||
let mut x1 = pos.x1();
|
||||
|
|
@ -970,10 +827,10 @@ impl ContainingNode for FloatNode {
|
|||
x2 = (v + bw).max(x1 + bw + bw);
|
||||
}
|
||||
if let Some(v) = new_y1 {
|
||||
y1 = (v - tpuh - bw).min(y2 - bw - tpuh - bw);
|
||||
y1 = (v - bw).min(y2 - bw - bw);
|
||||
}
|
||||
if let Some(v) = new_y2 {
|
||||
y2 = (v + bw).max(y1 + bw + tpuh + bw);
|
||||
y2 = (v + bw).max(y1 + bw + bw);
|
||||
}
|
||||
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
|
||||
if new_pos != pos {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue