diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index cc53c5ff..429ab199 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,9 +1,9 @@ use jay_config::embedded::grab_input_device; use jay_config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT}; use jay_config::keyboard::syms::{ - SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_p, SYM_period, - SYM_q, SYM_r, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, SYM_F2, SYM_F3, SYM_F4, - SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9, + SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_m, SYM_p, + SYM_period, SYM_q, SYM_r, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, SYM_F2, + SYM_F3, SYM_F4, SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9, }; use jay_config::theme::{get_title_height, set_title_color, set_title_height, Color}; use jay_config::Axis::{Horizontal, Vertical}; @@ -55,6 +55,10 @@ fn configure_seat(s: Seat) { s.set_split(s.split().other()); }); + s.bind(MOD | SYM_m, move || { + s.set_mono(!s.mono()); + }); + s.bind(MOD | SYM_f, move || { s.focus_parent(); }); diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index c81ccb5c..423a3551 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -185,6 +185,17 @@ impl Client { } } + pub fn mono(&self, seat: Seat) -> bool { + let res = self.with_response(|| self.send(&ClientMessage::GetMono { seat })); + match res { + Response::GetMono { mono } => mono, + _ => { + log::error!("Server did not send a response to a get_mono request"); + false + } + } + } + pub fn split(&self, seat: Seat) -> Axis { let res = self.with_response(|| self.send(&ClientMessage::GetSplit { seat })); match res { @@ -246,6 +257,10 @@ impl Client { self.send(&ClientMessage::SetBorderWidth { width }) } + pub fn set_mono(&self, seat: Seat, mono: bool) { + self.send(&ClientMessage::SetMono { seat, mono }); + } + pub fn set_split(&self, seat: Seat, axis: Axis) { self.send(&ClientMessage::SetSplit { seat, axis }); } diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 6c8b3545..c2e8af0b 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -65,6 +65,13 @@ pub enum ClientMessage<'a> { seat: Seat, axis: Axis, }, + GetMono { + seat: Seat, + }, + SetMono { + seat: Seat, + mono: bool, + }, RemoveSeat { seat: Seat, }, @@ -136,6 +143,7 @@ pub enum Response { None, GetSeats { seats: Vec }, GetSplit { axis: Axis }, + GetMono { mono: bool }, GetRepeatRate { rate: i32, delay: i32 }, ParseKeymap { keymap: Keymap }, CreateSeat { seat: Seat }, diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index 423dd83e..e11ac0a7 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -104,6 +104,16 @@ impl Seat { get!().seat_set_repeat_rate(self, rate, delay) } + pub fn mono(self) -> bool { + let mut res = false; + (|| res = get!().mono(self))(); + res + } + + pub fn set_mono(self, mono: bool) { + get!().set_mono(self, mono) + } + pub fn split(self) -> Axis { let mut res = Axis::Horizontal; (|| res = get!().split(self))(); diff --git a/src/config/handler.rs b/src/config/handler.rs index 35d6eca5..55e4d77d 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -204,6 +204,22 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_get_mono(&self, seat: Seat) -> Result<(), GetMonoError> { + let seat = self.get_seat(seat)?; + self.send(&ServerMessage::Response { + response: Response::GetMono { + mono: seat.get_mono().unwrap_or(false).into(), + }, + }); + Ok(()) + } + + fn handle_set_mono(&self, seat: Seat, mono: bool) -> Result<(), SetMonoError> { + let seat = self.get_seat(seat)?; + seat.set_mono(mono); + Ok(()) + } + fn handle_get_split(&self, seat: Seat) -> Result<(), GetSplitError> { let seat = self.get_seat(seat)?; self.send(&ServerMessage::Response { @@ -450,6 +466,8 @@ impl ConfigProxyHandler { self.handle_set_repeat_rate(seat, rate, delay)? } ClientMessage::SetSeat { device, seat } => self.handle_set_seat(device, seat)?, + ClientMessage::GetMono { seat } => self.handle_get_mono(seat)?, + ClientMessage::SetMono { seat, mono } => self.handle_set_mono(seat, mono)?, ClientMessage::GetSplit { seat } => self.handle_get_split(seat)?, ClientMessage::SetSplit { seat, axis } => self.handle_set_split(seat, axis)?, ClientMessage::AddShortcut { seat, mods, sym } => { @@ -505,6 +523,10 @@ enum CphError { FocusError(#[from] FocusError), #[error("Could not process a `move` request")] MoveError(#[from] MoveError), + #[error("Could not process a `set_mono` request")] + SetMonoError(#[from] SetMonoError), + #[error("Could not process a `get_mono` request")] + GetMonoError(#[from] GetMonoError), #[error("Could not process a `set_split` request")] SetSplitError(#[from] SetSplitError), #[error("Could not process a `get_split` request")] @@ -601,6 +623,20 @@ enum MoveError { } efrom!(MoveError, CphError); +#[derive(Debug, Error)] +enum SetMonoError { + #[error(transparent)] + CphError(#[from] Box), +} +efrom!(SetMonoError, CphError); + +#[derive(Debug, Error)] +enum GetMonoError { + #[error(transparent)] + CphError(#[from] Box), +} +efrom!(GetMonoError, CphError); + #[derive(Debug, Error)] enum SetSplitError { #[error(transparent)] diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 1340367d..b3253d8f 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -204,10 +204,18 @@ impl WlSeatGlobal { } } + pub fn get_mono(&self) -> Option { + self.keyboard_node.get().get_parent_mono() + } + pub fn get_split(&self) -> Option { self.keyboard_node.get().get_parent_split() } + pub fn set_mono(&self, mono: bool) { + self.keyboard_node.get().set_parent_mono(mono) + } + pub fn set_split(&self, axis: ContainerSplit) { self.keyboard_node.get().set_parent_split(axis) } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 7ead0145..4ae57942 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -641,10 +641,18 @@ impl Node for WlSurface { } } + fn get_parent_mono(&self) -> Option { + self.xdg.get().and_then(|x| x.get_mono()) + } + fn get_parent_split(&self) -> Option { self.xdg.get().and_then(|x| x.get_split()) } + fn set_parent_mono(&self, mono: bool) { + self.xdg.get().map(|x| x.set_mono(mono)); + } + fn set_parent_split(&self, split: ContainerSplit) { self.xdg.get().map(|x| x.set_split(split)); } diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index 24f81591..cadc5de3 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -83,10 +83,18 @@ pub trait XdgSurfaceExt: Debug { let _ = seat; } + fn get_mono(&self) -> Option { + None + } + fn get_split(&self) -> Option { None } + fn set_mono(&self, mono: bool) { + let _ = mono; + } + fn set_split(&self, split: ContainerSplit) { let _ = split; } @@ -166,10 +174,18 @@ impl XdgSurface { } } + pub fn get_mono(&self) -> Option { + self.ext.get().and_then(|e| e.get_mono()) + } + pub fn get_split(&self) -> Option { self.ext.get().and_then(|e| e.get_split()) } + pub fn set_mono(&self, mono: bool) { + self.ext.get().map(|e| e.set_mono(mono)); + } + pub fn set_split(&self, split: ContainerSplit) { self.ext.get().map(|e| e.set_split(split)); } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index a6f213c7..708258cb 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -327,7 +327,7 @@ impl XdgToplevel { _ => return, }; let extents = self.xdg.extents.get(); - parent.child_active_changed(self, self.active_surfaces.get() > 0); + parent.clone().child_active_changed(self, self.active_surfaces.get() > 0); parent.child_size_changed(self, extents.width(), extents.height()); parent.child_title_changed(self, self.title.borrow_mut().deref()); } @@ -503,10 +503,23 @@ impl XdgSurfaceExt for XdgToplevel { Self::toggle_floating(&self); } + fn get_mono(&self) -> Option { + self.parent_node.get().and_then(|p| p.get_mono()) + } + fn get_split(&self) -> Option { self.parent_node.get().and_then(|p| p.get_split()) } + fn set_mono(&self, mono: bool) { + let node = if mono { + Some(self as &dyn Node) + } else { + None + }; + self.parent_node.get().map(move |p| p.set_mono(node)); + } + fn set_split(&self, split: ContainerSplit) { self.parent_node.get().map(|p| p.set_split(split)); } diff --git a/src/main.rs b/src/main.rs index bafdbc4c..d5e00925 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,7 @@ use crate::render::RenderError; use crate::sighand::SighandError; use crate::state::State; use crate::tree::{ - container_layout, container_titles, float_layout, float_titles, DisplayNode, NodeIds, + container_layout, container_render_data, float_layout, float_titles, DisplayNode, NodeIds, }; use crate::udev::Udev; use crate::utils::clonecell::CloneCell; @@ -176,7 +176,7 @@ fn main_() -> Result<(), MainError> { input_device_handlers: Default::default(), theme: Default::default(), pending_container_layout: Default::default(), - pending_container_titles: Default::default(), + pending_container_render_data: Default::default(), pending_float_layout: Default::default(), pending_float_titles: Default::default(), dbus: Dbus::new(&engine, &run_toplevel), @@ -189,7 +189,7 @@ fn main_() -> Result<(), MainError> { let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone())); let _container_do_layout = engine.spawn2(Phase::Layout, container_layout(state.clone())); let _container_render_titles = - engine.spawn2(Phase::PostLayout, container_titles(state.clone())); + engine.spawn2(Phase::PostLayout, container_render_data(state.clone())); let _float_do_layout = engine.spawn2(Phase::Layout, float_layout(state.clone())); let _float_render_titles = engine.spawn2(Phase::PostLayout, float_titles(state.clone())); let socket_path = Acceptor::install(&state)?; diff --git a/src/render/renderer/framebuffer.rs b/src/render/renderer/framebuffer.rs index df33adda..37957b43 100644 --- a/src/render/renderer/framebuffer.rs +++ b/src/render/renderer/framebuffer.rs @@ -5,7 +5,7 @@ use crate::render::gl::sys::{ }; use crate::render::renderer::context::RenderContext; use crate::render::renderer::renderer::Renderer; -use crate::render::sys::{glBlendFunc, GL_ONE, GL_ONE_MINUS_SRC_ALPHA}; +use crate::render::sys::{glBlendFunc, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, glFlush}; use crate::tree::Node; use crate::State; use std::fmt::{Debug, Formatter}; @@ -74,6 +74,9 @@ impl Framebuffer { } } } + unsafe { + glFlush(); + } Ok(()) }); } diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index 9b30e6eb..00940098 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -16,24 +16,11 @@ use crate::render::sys::{glDisable, glEnable, GL_BLEND}; use crate::render::Texture; use crate::theme::Color; use crate::tree::{ - ContainerFocus, ContainerNode, ContainerSplit, FloatNode, Node, OutputNode, WorkspaceNode, + ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode, }; use crate::State; use std::ops::Deref; use std::rc::Rc; -use std::slice; - -const NON_COLOR: Color = Color::from_rgbaf(0.2, 0.2, 0.2, 1.0); -const CHILD_COLOR: Color = Color::from_rgbaf(0.8, 0.8, 0.8, 1.0); -const YES_COLOR: Color = Color::from_rgbaf(0.0, 0.0, 1.0, 1.0); - -fn focus_color(focus: ContainerFocus) -> Color { - match focus { - ContainerFocus::None => NON_COLOR, - ContainerFocus::Child => CHILD_COLOR, - ContainerFocus::Yes => YES_COLOR, - } -} pub struct Renderer<'a> { pub(super) ctx: &'a Rc, @@ -82,16 +69,21 @@ impl Renderer<'_> { 2.0 * (y as f32 / self.fb.height as f32) - 1.0 } + fn fill_boxes(&self, boxes: &[Rect], color: &Color) { + self.fill_boxes2(boxes, color, 0, 0); + } + + fn fill_boxes2(&self, boxes: &[Rect], color: &Color, dx: i32, dy: i32) { if boxes.is_empty() { return; } let mut pos = Vec::with_capacity(boxes.len() * 12); for bx in boxes { - let x1 = self.x_to_f(bx.x1()); - let y1 = self.y_to_f(bx.y1()); - let x2 = self.x_to_f(bx.x2()); - let y2 = self.y_to_f(bx.y2()); + let x1 = self.x_to_f(bx.x1() + dx); + let y1 = self.y_to_f(bx.y1() + dy); + let x2 = self.x_to_f(bx.x2() + dx); + let y2 = self.y_to_f(bx.y2() + dy); pos.extend_from_slice(&[ // triangle 1 x2, y1, // top right @@ -121,128 +113,35 @@ impl Renderer<'_> { } pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) { - let border_width = self.state.theme.border_width.get(); - let title_height = self.state.theme.title_height.get(); - let cwidth = container.width.get(); - let cheight = container.height.get(); - let num_children = container.num_children(); - let title_rect = Rect::new_sized(x, y, container.width.get(), title_height).unwrap(); - let underline_rect = - Rect::new_sized(x, y + title_height, container.width.get(), 1).unwrap(); - let mut titles = vec![]; - if let Some(child) = container.mono_child.get() { - let space_per_child = cwidth / num_children as i32; - let mut rem = cwidth % num_children as i32; - let mut pos = x; - let color = focus_color(ContainerFocus::None); - self.fill_boxes(slice::from_ref(&title_rect), &color); + { + let rd = container.render_data.borrow_mut(); + let c = self.state.theme.title_color.get(); + self.fill_boxes2(&rd.title_rects, &c, x, y); + let c = self.state.theme.active_title_color.get(); + self.fill_boxes2(&rd.active_title_rects, &c, x, y); + let c = self.state.theme.underline_color.get(); + self.fill_boxes2(&rd.underline_rects, &c, x, y); let c = self.state.theme.border_color.get(); - self.fill_boxes(slice::from_ref(&underline_rect), &c); - for child in container.children.iter() { - let focus = child.focus.get(); - let color = focus_color(focus); - let mut width = space_per_child; - if rem > 0 { - rem -= 1; - width += 1; - } - if let Some(title) = child.title_texture.get() { - titles.push((pos, 0, title)); - } - if focus != ContainerFocus::None { - let rect = Rect::new_sized(pos, y, width, title_height).unwrap(); - self.fill_boxes(slice::from_ref(&rect), &color); - } - pos += width as i32; + self.fill_boxes2(&rd.border_rects, &c, x, y); + for title in &rd.titles { + self.render_texture(&title.tex, x + title.x, y + title.y, ARGB8888); } + } + if let Some(child) = container.mono_child.get() { unsafe { - with_scissor(&container.mono_body.get(), || { + let body = container.mono_body.get().move_(x, y); + with_scissor(&body, || { let content = container.mono_content.get(); child.node.render(self, x + content.x1(), y + content.y1()); }); } } else { - let split = container.split.get(); - let num_title_rects = if split == ContainerSplit::Horizontal { - 1 - } else { - num_children - }; - let mut title_rects = Vec::with_capacity(num_title_rects); - let mut underline_rects = Vec::with_capacity(num_title_rects); - let mut border_rects = Vec::with_capacity(num_children - 1); - let mut active_rects = Vec::new(); - title_rects.push(title_rect); - underline_rects.push(underline_rect); - for (i, child) in container.children.iter().enumerate() { - let body = child.body.get(); - if let Some(title) = child.title_texture.get() { - titles.push((body.x1(), body.y1() - title_height - 1, title)); - } - if child.active.get() { - active_rects.push( - Rect::new_sized( - x + body.x1(), - y + body.y1() - title_height - 1, - body.width(), - title_height, - ) - .unwrap(), - ); - } - if i + 1 < num_children { - let border_rect = if split == ContainerSplit::Horizontal { - Rect::new_sized( - x + body.x2(), - y + body.y1() - title_height - 1, - border_width, - container.height.get(), - ) - .unwrap() - } else { - title_rects.push( - Rect::new_sized( - x, - y + body.y2() + border_width, - container.width.get(), - title_height, - ) - .unwrap(), - ); - underline_rects.push( - Rect::new_sized( - x, - y + body.y2() + border_width + title_height, - container.width.get(), - 1, - ) - .unwrap(), - ); - Rect::new_sized(x, y + body.y2(), container.width.get(), border_width) - .unwrap() - }; - border_rects.push(border_rect); - } - } - { - let c = self.state.theme.title_color.get(); - self.fill_boxes(&title_rects, &c); - let c = self.state.theme.active_title_color.get(); - self.fill_boxes(&active_rects, &c); - let c = self.state.theme.underline_color.get(); - self.fill_boxes(&underline_rects, &c); - let c = self.state.theme.border_color.get(); - self.fill_boxes(&border_rects, &c); - for (tx, ty, tex) in titles { - self.render_texture(&tex, x + tx, y + ty, ARGB8888); - } - } for child in container.children.iter() { let body = child.body.get(); - if body.x1() >= cwidth || body.y1() >= cheight { + if body.x1() >= container.width.get() || body.y1() >= container.height.get() { break; } - let body = body.move_(container.abs_x1.get(), container.abs_y1.get()); + let body = body.move_(x, y); unsafe { with_scissor(&body, || { let content = child.content.get(); diff --git a/src/state.rs b/src/state.rs index 890d7498..680e28b8 100644 --- a/src/state.rs +++ b/src/state.rs @@ -60,7 +60,7 @@ pub struct State { pub config: CloneCell>>, pub theme: Theme, pub pending_container_layout: AsyncQueue>, - pub pending_container_titles: AsyncQueue>, + pub pending_container_render_data: AsyncQueue>, pub pending_float_layout: AsyncQueue>, pub pending_float_titles: AsyncQueue>, pub dbus: Dbus, diff --git a/src/theme.rs b/src/theme.rs index c215ea9b..2521f931 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -30,10 +30,6 @@ impl Color { a: to_f32(a), } } - - pub const fn from_rgbaf(r: f32, g: f32, b: f32, a: f32) -> Self { - Self { r, g, b, a } - } } impl From for Color { diff --git a/src/tree.rs b/src/tree.rs index cb0ff88c..dd35c466 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -84,18 +84,34 @@ pub trait Node { let _ = title; } + fn get_parent_mono(&self) -> Option { + None + } + fn get_parent_split(&self) -> Option { None } + fn set_parent_mono(&self, mono: bool) { + let _ = mono; + } + fn set_parent_split(&self, split: ContainerSplit) { let _ = split; } + fn get_mono(&self) -> Option { + None + } + fn get_split(&self) -> Option { None } + fn set_mono(self: Rc, child: Option<&dyn Node>) { + let _ = child; + } + fn set_split(self: Rc, split: ContainerSplit) { let _ = split; } @@ -209,7 +225,7 @@ pub trait Node { let _ = (child, width, height); } - fn child_active_changed(&self, child: &dyn Node, active: bool) { + fn child_active_changed(self: Rc, child: &dyn Node, active: bool) { let _ = (child, active); } diff --git a/src/tree/container.rs b/src/tree/container.rs index eac647bd..17b35cef 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -54,6 +54,21 @@ pub enum ContainerFocus { tree_id!(ContainerNodeId); +pub struct ContainerTitle { + pub x: i32, + pub y: i32, + pub tex: Rc, +} + +#[derive(Default)] +pub struct ContainerRenderData { + pub title_rects: Vec, + pub active_title_rects: Vec, + pub border_rects: Vec, + pub underline_rects: Vec, + pub titles: Vec, +} + pub struct ContainerNode { pub id: ContainerNodeId, pub parent: CloneCell>, @@ -71,7 +86,7 @@ pub struct ContainerNode { pub content_height: Cell, pub sum_factors: Cell, layout_scheduled: Cell, - render_titles_scheduled: Cell, + compute_render_data_scheduled: Cell, num_children: NumCell, pub children: LinkedList, child_nodes: RefCell>>, @@ -79,6 +94,7 @@ pub struct ContainerNode { workspace: CloneCell>, seats: RefCell>, state: Rc, + pub render_data: RefCell, } impl Debug for ContainerNode { @@ -94,9 +110,7 @@ pub struct ContainerChild { pub body: Cell, pub content: Cell, factor: Cell, - pub focus: Cell, title: RefCell, - pub title_texture: CloneCell>>, } struct SeatState { @@ -143,9 +157,7 @@ impl ContainerNode { body: Cell::new(Default::default()), content: Cell::new(Default::default()), factor: Cell::new(1.0), - focus: Cell::new(ContainerFocus::None), title: Default::default(), - title_texture: Default::default(), }), ); let slf = Rc::new(Self { @@ -165,7 +177,7 @@ impl ContainerNode { content_height: Cell::new(0), sum_factors: Cell::new(1.0), layout_scheduled: Cell::new(false), - render_titles_scheduled: Cell::new(false), + compute_render_data_scheduled: Cell::new(false), num_children: NumCell::new(1), children, child_nodes: RefCell::new(child_nodes), @@ -173,15 +185,12 @@ impl ContainerNode { workspace: CloneCell::new(workspace.clone()), seats: RefCell::new(Default::default()), state: state.clone(), + render_data: Default::default(), }); child.set_parent(slf.clone()); slf } - pub fn num_children(&self) -> usize { - self.num_children.get() - } - pub fn prepend_child(self: &Rc, new: Rc) { if let Some(child) = self.children.first() { self.add_child_before_(&child, new); @@ -248,9 +257,7 @@ impl ContainerNode { body: Default::default(), content: Default::default(), factor: Cell::new(0.0), - focus: Cell::new(ContainerFocus::None), title: Default::default(), - title_texture: Default::default(), }), ); } @@ -287,7 +294,7 @@ impl ContainerNode { } pub fn on_colors_changed(self: &Rc) { - self.schedule_render_titles(); + self.schedule_compute_render_data(); } fn schedule_layout(self: &Rc) { @@ -297,6 +304,23 @@ impl ContainerNode { } fn perform_layout(self: &Rc) { + self.layout_scheduled.set(false); + if let Some(child) = self.mono_child.get() { + self.perform_mono_layout(&child); + } else { + self.perform_split_layout(); + } + self.schedule_compute_render_data(); + } + + fn perform_mono_layout(self: &Rc, child: &ContainerChild) { + let mb = self.mono_body.get(); + child.node.clone().change_extents(&mb.move_(self.abs_x1.get(), self.abs_y1.get())); + self.mono_content + .set(child.content.get().at_point(mb.x1(), mb.y1())); + } + + fn perform_split_layout(self: &Rc) { let sum_factors = self.sum_factors.get(); let border_width = self.state.theme.border_width.get(); let title_height = self.state.theme.title_height.get(); @@ -363,13 +387,11 @@ impl ContainerNode { } } self.sum_factors.set(1.0); - self.layout_scheduled.set(false); for child in self.children.iter() { let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); child.node.clone().change_extents(&body); child.position_content(); } - self.schedule_render_titles(); } fn update_content_size(&self) { @@ -393,6 +415,15 @@ impl ContainerNode { self.content_width.set(self.width.get()); } } + self.mono_body.set( + Rect::new_sized( + 0, + title_height + 1, + self.width.get(), + self.height.get().sub(title_height + 1).max(0), + ) + .unwrap(), + ); } fn pointer_move(self: &Rc, seat: &Rc, mut x: i32, mut y: i32) { @@ -482,55 +513,122 @@ impl ContainerNode { } fn update_title(self: &Rc) { - let split = match self.split.get() { - ContainerSplit::Horizontal => "H", - ContainerSplit::Vertical => "V", - }; let mut title = self.title.borrow_mut(); title.clear(); - title.push_str(split); - title.push_str("["); - for (i, c) in self.children.iter().enumerate() { - if i > 0 { - title.push_str(", "); + if let Some(mc) = self.mono_child.get() { + title.push_str("M["); + title.push_str(mc.title.borrow_mut().deref()); + title.push_str("]"); + } else { + let split = match self.split.get() { + ContainerSplit::Horizontal => "H", + ContainerSplit::Vertical => "V", + }; + title.push_str(split); + title.push_str("["); + for (i, c) in self.children.iter().enumerate() { + if i > 0 { + title.push_str(", "); + } + title.push_str(c.title.borrow_mut().deref()); } - title.push_str(c.title.borrow_mut().deref()); + title.push_str("]"); } - title.push_str("]"); self.parent.get().child_title_changed(&**self, &title); - self.schedule_render_titles(); } - fn schedule_render_titles(self: &Rc) { - if !self.render_titles_scheduled.replace(true) { - self.state.pending_container_titles.push(self.clone()); + fn schedule_compute_render_data(self: &Rc) { + if !self.compute_render_data_scheduled.replace(true) { + self.state.pending_container_render_data.push(self.clone()); } } - fn render_titles(&self) { - self.render_titles_scheduled.set(false); + fn compute_render_data(&self) { + self.compute_render_data_scheduled.set(false); + let mut rd = self.render_data.borrow_mut(); let theme = &self.state.theme; let th = theme.title_height.get(); + let bw = theme.border_width.get(); let font = theme.font.borrow_mut(); - for c in self.children.iter() { - c.title_texture.set(None); - let title = c.title.borrow_mut(); - let body = c.body.get(); - if title.is_empty() || th == 0 || body.width() == 0 { - continue; - } - let ctx = match self.state.render_ctx.get() { - Some(c) => c, - _ => continue, - }; - let texture = match text::render(&ctx, body.width(), th, &font, &title, Color::GREY) { - Ok(t) => t, - Err(e) => { - log::error!("Could not render title {}: {}", title, ErrorFmt(e)); - continue; + let cwidth = self.width.get(); + let cheight = self.height.get(); + let num_children = self.num_children.get() as i32; + let ctx = self.state.render_ctx.get(); + rd.titles.clear(); + rd.title_rects.clear(); + rd.active_title_rects.clear(); + rd.border_rects.clear(); + rd.underline_rects.clear(); + if self.mono_child.get().is_some() { + let content_width = self.width.get().sub(bw * (num_children - 1)).max(0); + let space_per_child = content_width / num_children; + let mut rem = content_width % num_children; + let mut pos = 0; + for (i, c) in self.children.iter().enumerate() { + if i > 0 { + rd.border_rects.push(Rect::new_sized(pos - bw, 0, bw, th).unwrap()); } - }; - c.title_texture.set(Some(texture)); + let mut width = space_per_child; + if rem > 0 { + rem -= 1; + width += 1; + } + let rect = Rect::new_sized(pos, 0, width, th).unwrap(); + if c.active.get() { + rd.active_title_rects.push(rect); + } else { + rd.title_rects.push(rect); + } + if let Some(ctx) = &ctx { + let title = c.title.borrow_mut(); + match text::render(&ctx, width, th, &font, &title, Color::GREY) { + Ok(t) => rd.titles.push(ContainerTitle { + x: pos, + y: 0, + tex: t, + }), + Err(e) => { + log::error!("Could not render title {}: {}", title, ErrorFmt(e)); + } + } + } + pos += width + bw; + } + rd.underline_rects.push(Rect::new_sized(0, th, cwidth, 1).unwrap()); + } else { + let split = self.split.get(); + for (i, c) in self.children.iter().enumerate() { + let body = c.body.get(); + if i > 0 { + let rect = if split == ContainerSplit::Horizontal { + Rect::new_sized(body.x1() - bw, 0, bw, cheight).unwrap() + } else { + Rect::new_sized(0, body.y1() - th - 1 - bw, cwidth, bw).unwrap() + }; + rd.border_rects.push(rect); + } + let rect = Rect::new_sized(body.x1(), body.y1() - th - 1, body.width(), th).unwrap(); + if c.active.get() { + rd.active_title_rects.push(rect); + } else { + rd.title_rects.push(rect); + } + let rect = Rect::new_sized(body.x1(), body.y1() - 1, body.width(), 1).unwrap(); + rd.underline_rects.push(rect); + if let Some(ctx) = &ctx { + let title = c.title.borrow_mut(); + match text::render(&ctx, body.width(), th, &font, &title, Color::GREY) { + Ok(t) => rd.titles.push(ContainerTitle { + x: body.x1(), + y: body.y1() - th - 1, + tex: t, + }), + Err(e) => { + log::error!("Could not render title {}: {}", title, ErrorFmt(e)); + } + } + } + } } } } @@ -555,11 +653,11 @@ pub async fn container_layout(state: Rc) { } } -pub async fn container_titles(state: Rc) { +pub async fn container_render_data(state: Rc) { loop { - let container = state.pending_container_titles.pop().await; - if container.render_titles_scheduled.get() { - container.render_titles(); + let container = state.pending_container_render_data.pop().await; + if container.compute_render_data_scheduled.get() { + container.compute_render_data(); } } } @@ -617,12 +715,33 @@ impl Node for ContainerNode { ct.push_str(title); } self.update_title(); + self.schedule_compute_render_data(); + } + + fn get_mono(&self) -> Option { + Some(self.mono_child.get().is_some()) } fn get_split(&self) -> Option { Some(self.split.get()) } + fn set_mono(self: Rc, child: Option<&dyn Node>) { + if self.mono_child.get().is_some() != child.is_some() { + let children = self.child_nodes.borrow_mut(); + let child = match child { + Some(c) => match children.get(&c.id()) { + Some(c) => Some(c.to_ref()), + _ => return, + }, + _ => None, + }; + self.mono_child.set(child); + self.schedule_layout(); + self.update_title(); + } + } + fn set_split(self: Rc, split: ContainerSplit) { if self.split.replace(split) != split { self.update_content_size(); @@ -636,11 +755,15 @@ impl Node for ContainerNode { } fn do_focus(self: Rc, seat: &Rc, direction: Direction) { - let node = match direction { - Direction::Left => self.children.last(), - Direction::Down => self.children.first(), - Direction::Up => self.children.last(), - Direction::Right => self.children.first(), + let node = if let Some(cn) = self.mono_child.get() { + Some(cn) + } else { + match direction { + Direction::Left => self.children.last(), + Direction::Down => self.children.first(), + Direction::Up => self.children.last(), + Direction::Right => self.children.first(), + } }; if let Some(node) = node { node.node.clone().do_focus(seat, direction); @@ -671,9 +794,14 @@ impl Node for ContainerNode { Some(c) => c.to_ref(), _ => return, }; - let in_line = match self.split.get() { - ContainerSplit::Horizontal => matches!(direction, Direction::Left | Direction::Right), - ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down), + let mc = self.mono_child.get(); + let in_line = if mc.is_some() { + matches!(direction, Direction::Left | Direction::Right) + } else { + match self.split.get() { + ContainerSplit::Horizontal => matches!(direction, Direction::Left | Direction::Right), + ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down), + } }; if !in_line { self.parent @@ -700,6 +828,12 @@ impl Node for ContainerNode { return; } }; + if mc.is_some() { + self.mono_child.set(Some(sibling.clone())); + let body = self.mono_body.get(); + self.mono_content.set(sibling.content.get().at_point(body.x1(), body.y1())); + sibling.node.clone().change_extents(&body.move_(self.abs_x1.get(), self.abs_y1.get())); + } sibling.node.clone().do_focus(seat, direction); } // @@ -902,9 +1036,7 @@ impl Node for ContainerNode { body: Cell::new(node.body.get()), content: Cell::new(node.content.get()), factor: Cell::new(node.factor.get()), - focus: Cell::new(node.focus.get()), title: Default::default(), - title_texture: Default::default(), }); let body = link.body.get(); drop(node); @@ -954,15 +1086,22 @@ impl Node for ContainerNode { let rect = Rect::new(0, 0, width, height).unwrap(); node.content.set(rect); node.position_content(); + if let Some(mono) = self.mono_child.get() { + if mono.node.id() == node.node.id() { + let body = self.mono_body.get(); + self.mono_content.set(rect.at_point(body.x1(), body.y1())); + } + } } } - fn child_active_changed(&self, child: &dyn Node, active: bool) { + fn child_active_changed(self: Rc, child: &dyn Node, active: bool) { let node = match self.child_nodes.borrow_mut().get(&child.id()) { Some(l) => l.to_ref(), None => return, }; node.active.set(active); + self.schedule_compute_render_data(); } fn pointer_enter(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { @@ -1027,9 +1166,14 @@ impl Node for ContainerNode { .get() .child_size_changed(&*self, rect.width(), rect.height()); } else { - for child in self.children.iter() { - let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); - child.node.clone().change_extents(&body); + if let Some(c) = self.mono_child.get() { + let body = self.mono_body.get().move_(self.abs_x1.get(), self.abs_y1.get()); + c.node.clone().change_extents(&body); + } else { + for child in self.children.iter() { + let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); + child.node.clone().change_extents(&body); + } } } } @@ -1043,7 +1187,7 @@ impl Node for ContainerNode { fn set_parent(self: Rc, parent: Rc) { self.parent.set(parent.clone()); - parent.child_active_changed(&*self, self.active.get()); + parent.clone().child_active_changed(&*self, self.active.get()); parent.child_size_changed(&*self, self.width.get(), self.height.get()); parent .clone() diff --git a/src/tree/float.rs b/src/tree/float.rs index b56bd449..2b44c817 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -437,7 +437,7 @@ impl Node for FloatNode { self.workspace_link.set(None); } - fn child_active_changed(&self, _child: &dyn Node, active: bool) { + fn child_active_changed(self: Rc, _child: &dyn Node, active: bool) { self.active.set(active); }