From 195a92d98bf31dcb585fcefe51cf87c6d446409a Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 17 Feb 2022 19:12:52 +0100 Subject: [PATCH] autocommit 2022-02-17 19:12:52 CET --- Cargo.lock | 15 +- default-config/Cargo.toml | 1 + default-config/src/lib.rs | 36 +++- i4config/src/_private/client.rs | 51 ++++++ i4config/src/_private/ipc.rs | 27 +++ i4config/src/lib.rs | 7 +- i4config/src/theme.rs | 45 +++++ src/backend.rs | 3 +- src/backends/dummy.rs | 11 +- src/backends/mod.rs | 2 +- src/backends/xorg.rs | 16 +- src/config/handler.rs | 154 +++++++++++++----- src/ifs/wl_seat.rs | 4 + src/ifs/wl_seat/pointer_owner.rs | 4 +- src/ifs/wl_surface.rs | 8 +- src/ifs/wl_surface/xdg_surface.rs | 8 + .../wl_surface/xdg_surface/xdg_toplevel.rs | 21 +++ src/main.rs | 8 +- src/render/renderer/framebuffer.rs | 1 + src/render/renderer/renderer.rs | 78 +++++---- src/state.rs | 10 +- src/tasks/device.rs | 14 +- src/tasks/layout.rs | 0 src/tasks/mod.rs | 9 + src/tasks/output.rs | 1 + src/theme.rs | 60 +++++++ src/tree/container.rs | 130 +++++++++------ src/tree/mod.rs | 50 +++++- src/tree/workspace.rs | 11 +- 29 files changed, 610 insertions(+), 175 deletions(-) create mode 100644 i4config/src/theme.rs create mode 100644 src/tasks/layout.rs create mode 100644 src/theme.rs diff --git a/Cargo.lock b/Cargo.lock index ef5ed02b..fcb8703d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,6 +153,7 @@ version = "0.1.0" dependencies = [ "i4config", "log", + "rand", ] [[package]] @@ -474,14 +475,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -503,15 +503,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - [[package]] name = "regex" version = "1.5.4" diff --git a/default-config/Cargo.toml b/default-config/Cargo.toml index 13b24665..f4237c5e 100644 --- a/default-config/Cargo.toml +++ b/default-config/Cargo.toml @@ -9,3 +9,4 @@ crate-type = ["lib", "cdylib"] [dependencies] i4config = { path = "../i4config" } log = "0.4.14" +rand = "0.8.5" diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index 13981f8e..6738f0c3 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,8 +1,13 @@ -use i4config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT}; -use i4config::keyboard::syms::{SYM_h, SYM_j, SYM_k, SYM_l, SYM_r, SYM_t, SYM_y, SYM_b, SYM_Super_L}; -use i4config::Direction::{Down, Left, Right, Up}; -use i4config::{config, create_seat, input_devices, on_new_input_device, Command, Seat, InputDevice}; use i4config::embedded::grab_keyboard; +use i4config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT}; +use i4config::keyboard::syms::{SYM_Super_L, SYM_b, SYM_comma, SYM_h, SYM_j, SYM_k, SYM_l, SYM_period, SYM_r, SYM_t, SYM_y, SYM_d, SYM_v}; +use i4config::theme::{get_title_height, set_title_color, set_title_height, Color}; +use i4config::Direction::{Down, Left, Right, Up}; +use i4config::{ + config, create_seat, input_devices, on_new_input_device, Command, InputDevice, Seat, +}; +use rand::Rng; +use i4config::Axis::{Horizontal, Vertical}; const MOD: Modifiers = ALT; @@ -20,11 +25,28 @@ fn configure_seat(s: Seat) { s.bind(CTRL | SHIFT | SYM_l, move || change_rate(-1)); s.bind(CTRL | SHIFT | SYM_r, move || change_rate(1)); + s.bind(MOD | SYM_comma, move || { + let mut rng = rand::thread_rng(); + set_title_color(Color { + r: rng.gen(), + g: rng.gen(), + b: rng.gen(), + a: rng.gen(), + }) + }); + + s.bind(MOD | SYM_period, move || { + set_title_height(get_title_height() + 1) + }); + s.bind(MOD | SYM_h, move || s.focus(Left)); s.bind(MOD | SYM_j, move || s.focus(Down)); s.bind(MOD | SYM_k, move || s.focus(Up)); s.bind(MOD | SYM_l, move || s.focus(Right)); + s.bind(MOD | SYM_d, move || s.create_split(Horizontal)); + s.bind(MOD | SYM_v, move || s.create_split(Vertical)); + s.bind(MOD | SYM_t, move || { s.set_split(s.split().other()); }); @@ -39,7 +61,11 @@ fn configure_seat(s: Seat) { fn do_grab(s: Seat, grab: bool) { for device in s.input_devices() { if let InputDevice::Keyboard(kb) = device { - log::info!("{}rabbing keyboard {:?}", if grab { "G" } else { "Ung" }, kb.0); + log::info!( + "{}rabbing keyboard {:?}", + if grab { "G" } else { "Ung" }, + kb.0 + ); grab_keyboard(kb, grab); } } diff --git a/i4config/src/_private/client.rs b/i4config/src/_private/client.rs index f78e50d1..f93d7459 100644 --- a/i4config/src/_private/client.rs +++ b/i4config/src/_private/client.rs @@ -1,6 +1,7 @@ use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage}; use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION}; use crate::keyboard::keymap::Keymap; +use crate::theme::Color; use crate::{Axis, Command, Direction, InputDevice, Keyboard, LogLevel, ModifiedKeySym, Seat}; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; @@ -195,10 +196,60 @@ impl Client { } } + pub fn set_title_color(&self, color: Color) { + self.send(&ClientMessage::SetTitleColor { color }); + } + + pub fn set_border_color(&self, color: Color) { + self.send(&ClientMessage::SetBorderColor { color }); + } + + pub fn set_title_underline_color(&self, color: Color) { + self.send(&ClientMessage::SetTitleUnderlineColor { color }); + } + + pub fn set_background_color(&self, color: Color) { + self.send(&ClientMessage::SetBackgroundColor { color }); + } + + pub fn get_title_height(&self) -> i32 { + let resp = self.with_response(|| self.send(&ClientMessage::GetTitleHeight)); + match resp { + Response::GetTitleHeight { height } => height, + _ => { + log::warn!("Server did not reply to a get_title_height request"); + 0 + } + } + } + + pub fn get_border_width(&self) -> i32 { + let resp = self.with_response(|| self.send(&ClientMessage::GetBorderWidth)); + match resp { + Response::GetBorderWidth { width } => width, + _ => { + log::warn!("Server did not reply to a get_border_width request"); + 0 + } + } + } + + pub fn set_title_height(&self, height: i32) { + self.send(&ClientMessage::SetTitleHeight { height }) + } + + pub fn set_border_width(&self, width: i32) { + self.send(&ClientMessage::SetBorderWidth { width }) + } + pub fn set_split(&self, seat: Seat, axis: Axis) { self.send(&ClientMessage::SetSplit { seat, axis }); } + pub fn create_split(&self, seat: Seat, axis: Axis) { + self.send(&ClientMessage::CreateSplit { seat, axis }); + } + pub fn create_seat(&self, name: &str) -> Seat { let response = self.with_response(|| self.send(&ClientMessage::CreateSeat { name })); match response { diff --git a/i4config/src/_private/ipc.rs b/i4config/src/_private/ipc.rs index 2fa98246..25c08e70 100644 --- a/i4config/src/_private/ipc.rs +++ b/i4config/src/_private/ipc.rs @@ -1,6 +1,7 @@ use crate::keyboard::keymap::Keymap; use crate::keyboard::mods::Modifiers; use crate::keyboard::syms::KeySym; +use crate::theme::Color; use crate::{Axis, Direction, InputDevice, Keyboard, LogLevel, Seat}; use bincode::{BorrowDecode, Decode, Encode}; @@ -94,6 +95,30 @@ pub enum ClientMessage<'a> { kb: Keyboard, grab: bool, }, + GetTitleHeight, + GetBorderWidth, + SetTitleHeight { + height: i32, + }, + SetBorderWidth { + width: i32, + }, + SetTitleColor { + color: Color, + }, + SetTitleUnderlineColor { + color: Color, + }, + SetBorderColor { + color: Color, + }, + SetBackgroundColor { + color: Color, + }, + CreateSplit { + seat: Seat, + axis: Axis, + }, } #[derive(Encode, Decode, Debug)] @@ -105,6 +130,8 @@ pub enum Response { ParseKeymap { keymap: Keymap }, CreateSeat { seat: Seat }, GetInputDevices { devices: Vec }, + GetTitleHeight { height: i32 }, + GetBorderWidth { width: i32 }, } #[derive(Encode, Decode, Debug)] diff --git a/i4config/src/lib.rs b/i4config/src/lib.rs index 7daf632a..5e8d0df9 100644 --- a/i4config/src/lib.rs +++ b/i4config/src/lib.rs @@ -9,8 +9,9 @@ use std::collections::HashMap; mod macros; #[doc(hidden)] pub mod _private; -pub mod keyboard; pub mod embedded; +pub mod keyboard; +pub mod theme; #[derive(Encode, Decode, Copy, Clone, Debug)] pub enum LogLevel { @@ -129,6 +130,10 @@ impl Seat { (|| res = get!().get_input_devices(Some(self)))(); res } + + pub fn create_split(self, axis: Axis) { + get!().create_split(self, axis); + } } pub fn get_seats() -> Vec { diff --git a/i4config/src/theme.rs b/i4config/src/theme.rs new file mode 100644 index 00000000..cb5020ba --- /dev/null +++ b/i4config/src/theme.rs @@ -0,0 +1,45 @@ +use bincode::{BorrowDecode, Encode}; + +#[derive(Encode, BorrowDecode, Debug)] +pub struct Color { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, +} + +pub fn set_title_color(color: Color) { + get!().set_title_color(color) +} + +pub fn set_title_underline_color(color: Color) { + get!().set_title_underline_color(color) +} + +pub fn set_border_color(color: Color) { + get!().set_border_color(color) +} + +pub fn set_background_color(color: Color) { + get!().set_background_color(color) +} + +pub fn get_title_height() -> i32 { + let mut res = 0; + (|| res = get!().get_title_height())(); + res +} + +pub fn get_border_width() -> i32 { + let mut res = 0; + (|| res = get!().get_border_width())(); + res +} + +pub fn set_title_height(height: i32) { + get!().set_title_height(height) +} + +pub fn set_border_width(width: i32) { + get!().set_border_width(width) +} diff --git a/src/backend.rs b/src/backend.rs index 32d76201..4664affc 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -6,8 +6,7 @@ linear_ids!(OutputIds, OutputId); linear_ids!(KeyboardIds, KeyboardId); linear_ids!(MouseIds, MouseId); -pub trait Backend { -} +pub trait Backend {} pub trait Output { fn id(&self) -> OutputId; diff --git a/src/backends/dummy.rs b/src/backends/dummy.rs index e3a544e0..9f8605ac 100644 --- a/src/backends/dummy.rs +++ b/src/backends/dummy.rs @@ -1,15 +1,12 @@ -use std::rc::Rc; use crate::backend::Backend; +use std::rc::Rc; -pub struct DummyBackend { - -} +pub struct DummyBackend {} impl DummyBackend { pub fn new() -> Rc { - Rc::new(Self { }) + Rc::new(Self {}) } } -impl Backend for DummyBackend { -} +impl Backend for DummyBackend {} diff --git a/src/backends/mod.rs b/src/backends/mod.rs index 807f1e10..03fd5cba 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -1,2 +1,2 @@ -pub mod xorg; pub mod dummy; +pub mod xorg; diff --git a/src/backends/xorg.rs b/src/backends/xorg.rs index 3939d6b2..33a9c6f4 100644 --- a/src/backends/xorg.rs +++ b/src/backends/xorg.rs @@ -1,4 +1,7 @@ -use crate::backend::{BackendEvent, KeyState, Keyboard, KeyboardEvent, KeyboardId, Mouse, MouseEvent, MouseId, Output, OutputId, ScrollAxis, Backend}; +use crate::backend::{ + Backend, BackendEvent, KeyState, Keyboard, KeyboardEvent, KeyboardId, Mouse, MouseEvent, + MouseId, Output, OutputId, ScrollAxis, +}; use crate::drm::drm::{Drm, DrmError}; use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}; use crate::drm::{ModifiedFormat, INVALID_MODIFIER}; @@ -211,8 +214,7 @@ pub struct XorgBackend { b: Cell, } -impl Backend for XorgBackend { -} +impl Backend for XorgBackend {} fn get_drm(con: &XcbCon) -> Result { unsafe { @@ -1098,7 +1100,9 @@ impl Keyboard for XorgSeat { 0, ptr::null(), ); - let res = con.input.xcb_input_xi_grab_device_reply(con.c, res, &mut err); + let res = con + .input + .xcb_input_xi_grab_device_reply(con.c, res, &mut err); let res = match con.check(res, err) { Ok(r) => r, Err(e) => { @@ -1110,7 +1114,9 @@ impl Keyboard for XorgSeat { log::error!("Could not grab device {}: status = {}", self.kb, res.status); } } else { - let cookie = con.input.xcb_input_xi_ungrab_device_checked(con.c, 0, self.kb); + let cookie = con + .input + .xcb_input_xi_ungrab_device_checked(con.c, 0, self.kb); if let Err(e) = con.check_cookie(cookie) { log::error!("Could not ungrab device {}: {}", self.kb, ErrorFmt(e)); } diff --git a/src/config/handler.rs b/src/config/handler.rs index 944e366c..9699a7eb 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1,6 +1,6 @@ use crate::backend::{KeyboardId, MouseId}; use crate::ifs::wl_seat::{SeatId, WlSeatGlobal}; -use crate::state::{DeviceHandlerData}; +use crate::state::DeviceHandlerData; use crate::tree::ContainerSplit; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::debug_fn::debug_fn; @@ -54,7 +54,7 @@ impl ConfigProxyHandler { msg: &str, file: Option<&str>, line: Option, - ) -> Result<(), LogError> { + ) { let level = match level { LogLevel::Error => Level::Error, LogLevel::Warn => Level::Warn, @@ -74,10 +74,9 @@ impl ConfigProxyHandler { Ok(()) }); log::log!(level, "{:?}", debug); - Ok(()) } - fn handle_create_seat(&self, name: &str) -> Result<(), CreateSeatError> { + fn handle_create_seat(&self, name: &str) { let global_name = self.state.globals.name(); let seat = WlSeatGlobal::new(global_name, name, &self.state); self.state.globals.add_global(&self.state, &seat); @@ -86,7 +85,6 @@ impl ConfigProxyHandler { seat: Seat(seat.id().raw() as _), }, }); - Ok(()) } fn handle_parse_keymap(&self, keymap: &str) -> Result<(), ParseKeymapError> { @@ -248,7 +246,7 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_get_input_devices(&self, seat: Option) -> Result<(), GetInputDevicesError> { + fn handle_get_input_devices(&self, seat: Option) { let id = seat.map(|s| SeatId::from_raw(s.0 as _)); let matches = |dhd: &DeviceHandlerData| { let id = match id { @@ -280,10 +278,9 @@ impl ConfigProxyHandler { self.send(&ServerMessage::Response { response: Response::GetInputDevices { devices: res }, }); - Ok(()) } - fn handle_get_seats(&self) -> Result<(), GetSeatsError> { + fn handle_get_seats(&self) { let seats = { let seats = self.state.globals.seats.lock(); seats @@ -294,7 +291,6 @@ impl ConfigProxyHandler { self.send(&ServerMessage::Response { response: Response::GetSeats { seats }, }); - Ok(()) } fn handle_run( @@ -311,16 +307,78 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_grab( - &self, - kb: Keyboard, - grab: bool, - ) -> Result<(), GrabError> { + fn handle_grab(&self, kb: Keyboard, grab: bool) -> Result<(), GrabError> { let kb = self.get_kb(kb)?; kb.grab(grab); Ok(()) } + fn handle_get_title_height(&self) { + self.send(&ServerMessage::Response { + response: Response::GetTitleHeight { + height: self.state.theme.title_height.get(), + }, + }); + } + + fn handle_get_border_width(&self) { + self.send(&ServerMessage::Response { + response: Response::GetBorderWidth { + width: self.state.theme.border_width.get(), + }, + }); + } + + fn handle_create_split(&self, seat: Seat, axis: Axis) -> Result<(), CreateSplitError> { + let seat = self.get_seat(seat)?; + seat.create_split(axis.into()); + Ok(()) + } + + fn handle_set_title_height(&self, height: i32) -> Result<(), SetTitleHeightError> { + if height < 0 { + return Err(SetTitleHeightError::Negative(height)); + } + if height > 1000 { + return Err(SetTitleHeightError::Excessive(height)); + } + self.state.theme.title_height.set(height); + self.state.theme.version.fetch_add(1); + self.state.root.needs_layout.set(true); + self.state.pending_layout.push(self.state.root.clone()); + Ok(()) + } + + fn handle_set_border_width(&self, width: i32) -> Result<(), SetBorderWidthError> { + if width < 0 { + return Err(SetBorderWidthError::Negative(width)); + } + if width > 1000 { + return Err(SetBorderWidthError::Excessive(width)); + } + self.state.theme.border_width.set(width); + self.state.theme.version.fetch_add(1); + self.state.root.needs_layout.set(true); + self.state.pending_layout.push(self.state.root.clone()); + Ok(()) + } + + fn handle_set_title_color(&self, color: i4config::theme::Color) { + self.state.theme.title_color.set(color.into()); + } + + fn handle_set_border_color(&self, color: i4config::theme::Color) { + self.state.theme.border_color.set(color.into()); + } + + fn handle_set_background_color(&self, color: i4config::theme::Color) { + self.state.theme.background_color.set(color.into()); + } + + fn handle_set_title_underline_color(&self, color: i4config::theme::Color) { + self.state.theme.underline_color.set(color.into()); + } + pub fn handle_request(&self, msg: &[u8]) { if let Err(e) = self.handle_request_(msg) { log::error!("Could not handle client request: {}", ErrorFmt(e)); @@ -339,8 +397,8 @@ impl ConfigProxyHandler { msg, file, line, - } => self.handle_log_request(level, msg, file, line)?, - ClientMessage::CreateSeat { name } => self.handle_create_seat(name)?, + } => self.handle_log_request(level, msg, file, line), + ClientMessage::CreateSeat { name } => self.handle_create_seat(name), ClientMessage::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?, ClientMessage::SeatSetKeymap { seat, keymap } => { self.handle_set_keymap(seat, keymap)? @@ -360,11 +418,22 @@ impl ConfigProxyHandler { } ClientMessage::Focus { seat, direction } => self.handle_focus(seat, direction)?, ClientMessage::Move { seat, direction } => {} - ClientMessage::GetInputDevices { seat } => self.handle_get_input_devices(seat)?, - ClientMessage::GetSeats => self.handle_get_seats()?, + ClientMessage::GetInputDevices { seat } => self.handle_get_input_devices(seat), + ClientMessage::GetSeats => self.handle_get_seats(), ClientMessage::RemoveSeat { .. } => {} ClientMessage::Run { prog, args, env } => self.handle_run(prog, args, env)?, ClientMessage::GrabKb { kb, grab } => self.handle_grab(kb, grab)?, + ClientMessage::SetTitleHeight { height } => self.handle_set_title_height(height)?, + ClientMessage::SetBorderWidth { width } => self.handle_set_border_width(width)?, + ClientMessage::SetTitleColor { color } => self.handle_set_title_color(color), + ClientMessage::SetTitleUnderlineColor { color } => { + self.handle_set_title_underline_color(color) + } + ClientMessage::SetBorderColor { color } => self.handle_set_border_color(color), + ClientMessage::SetBackgroundColor { color } => self.handle_set_background_color(color), + ClientMessage::GetTitleHeight => self.handle_get_title_height(), + ClientMessage::GetBorderWidth => self.handle_get_border_width(), + ClientMessage::CreateSplit { seat, axis } => self.handle_create_split(seat, axis)?, } Ok(()) } @@ -372,10 +441,6 @@ impl ConfigProxyHandler { #[derive(Debug, Error)] enum CphError { - #[error("Could not process a `log` request")] - LogError(#[from] LogError), - #[error("Could not process a `create_seat` request")] - CreateSeatError(#[from] CreateSeatError), #[error("Could not process a `parse_keymap` request")] ParseKeymapError(#[from] ParseKeymapError), #[error("Could not process a `set_seat` request")] @@ -384,10 +449,6 @@ enum CphError { AddShortcutError(#[from] AddShortcutError), #[error("Could not process a `remove_shortcut` request")] RemoveShortcutError(#[from] RemoveShortcutError), - #[error("Could not process a `get_input_devices` request")] - GetInputDevicesError(#[from] GetInputDevicesError), - #[error("Could not process a `get_seats` request")] - GetSeatsError(#[from] GetSeatsError), #[error("Could not process a `set_keymap` request")] SeatSetKeymapError(#[from] SeatSetKeymapError), #[error("Could not process a `get_repeat_rate` request")] @@ -404,6 +465,12 @@ enum CphError { RunError(#[from] RunError), #[error("Could not process a `grab` request")] GrabError(#[from] GrabError), + #[error("Could not process a `create_split` request")] + CreateSplitError(#[from] CreateSplitError), + #[error("Could not process a `set_title_height` request")] + SetTitleHeightError(#[from] SetTitleHeightError), + #[error("Could not process a `set_border_width` request")] + SetBorderWidthError(#[from] SetBorderWidthError), #[error("Device {0:?} does not exist")] DeviceDoesNotExist(InputDevice), #[error("Device {0:?} does not exist")] @@ -416,12 +483,6 @@ enum CphError { ParsingFailed(#[source] DecodeError), } -#[derive(Debug, Error)] -enum LogError {} - -#[derive(Debug, Error)] -enum CreateSeatError {} - #[derive(Debug, Error)] enum ParseKeymapError { #[error("Parsing failed")] @@ -449,12 +510,6 @@ enum RemoveShortcutError { } efrom!(RemoveShortcutError, CphError); -#[derive(Debug, Error)] -enum GetInputDevicesError {} - -#[derive(Debug, Error)] -enum GetSeatsError {} - #[derive(Debug, Error)] enum SeatSetKeymapError { #[error(transparent)] @@ -513,3 +568,26 @@ enum GrabError { CphError(#[from] Box), } efrom!(GrabError, CphError); + +#[derive(Debug, Error)] +enum SetTitleHeightError { + #[error("The height {0} is negative")] + Negative(i32), + #[error("The height {0} is larger than the maximum 1000")] + Excessive(i32), +} + +#[derive(Debug, Error)] +enum SetBorderWidthError { + #[error("The width {0} is negative")] + Negative(i32), + #[error("The width {0} is larger than the maximum 1000")] + Excessive(i32), +} + +#[derive(Debug, Error)] +enum CreateSplitError { + #[error(transparent)] + CphError(#[from] Box), +} +efrom!(CreateSplitError, CphError); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index cd9cfdfd..30a3a7c7 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -195,6 +195,10 @@ impl WlSeatGlobal { self.keyboard_node.get().set_parent_split(axis) } + pub fn create_split(&self, axis: ContainerSplit) { + self.keyboard_node.get().create_split(axis) + } + pub fn get_rate(&self) -> (i32, i32) { self.repeat_rate.get() } diff --git a/src/ifs/wl_seat/pointer_owner.rs b/src/ifs/wl_seat/pointer_owner.rs index 2e09d080..3ad0ee10 100644 --- a/src/ifs/wl_seat/pointer_owner.rs +++ b/src/ifs/wl_seat/pointer_owner.rs @@ -147,7 +147,7 @@ impl PointerOwner for DefaultPointerOwner { } if (stack.len(), found_tree.len()) == (divergence, divergence) { if let Some(node) = found_tree.last() { - node.node + node.node.clone() .motion(seat, x.apply_fract(node.x), y.apply_fract(node.y)); } } else { @@ -242,7 +242,7 @@ impl PointerOwner for GrabPointerOwner { let (x, y) = seat.pos.get(); let pos = self.node.absolute_position(); let (x_int, y_int) = pos.translate(x.round_down(), y.round_down()); - self.node + self.node.clone() .motion(seat, x.apply_fract(x_int), y.apply_fract(y_int)); } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 302f8ab4..28f9a690 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -618,6 +618,10 @@ impl Node for WlSurface { self.xdg.get().map(|x| x.set_split(split)); } + fn create_split(self: Rc, split: ContainerSplit) { + self.xdg.get().map(|x| x.create_split(split)); + } + fn move_focus(&self, seat: &Rc, direction: Direction) { let xdg = match self.xdg.get() { Some(x) => x, @@ -670,8 +674,8 @@ impl Node for WlSurface { seat.enter_surface(&self, x, y) } - fn motion(&self, seat: &Rc, x: Fixed, y: Fixed) { - seat.motion_surface(self, x, y) + fn motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { + seat.motion_surface(&*self, x, y) } fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index f99aded1..75f07412 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -83,6 +83,10 @@ pub trait XdgSurfaceExt: Debug { let _ = split; } + fn create_split(self: Rc, split: ContainerSplit) { + let _ = split; + } + fn move_focus(self: Rc, seat: &Rc, direction: Direction) { let _ = seat; let _ = direction; @@ -158,6 +162,10 @@ impl XdgSurface { self.ext.get().map(|e| e.set_split(split)); } + pub fn create_split(&self, split: ContainerSplit) { + self.ext.get().map(|e| e.create_split(split)); + } + pub fn move_focus(&self, seat: &Rc, direction: Direction) { let ext = match self.ext.get() { None => return, diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 1f4ea6ec..b798359c 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -373,6 +373,7 @@ impl XdgToplevel { &workspace, workspace.clone(), self.clone(), + ContainerSplit::Horizontal, )); workspace.set_container(&container); self.parent_node.set(Some(container)); @@ -492,6 +493,26 @@ impl XdgSurfaceExt for XdgToplevel { self.parent_node.get().map(|p| p.set_split(split)); } + fn create_split(self: Rc, split: ContainerSplit) { + let ws = match self.xdg.workspace.get() { + Some(ws) => ws, + _ => return, + }; + let pn = match self.parent_node.get() { + Some(pn) => pn, + _ => return, + }; + let cn = Rc::new(ContainerNode::new( + &self.xdg.surface.client.state, + &ws, + pn.clone(), + self.clone(), + split, + )); + self.parent_node.set(Some(cn.clone())); + pn.replace_child(&*self, cn); + } + fn move_focus(self: Rc, seat: &Rc, direction: Direction) { let pn = match self.parent_node.get() { Some(pn) => pn, diff --git a/src/main.rs b/src/main.rs index 318793d1..892da8e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use crate::acceptor::AcceptorError; use crate::async_engine::AsyncError; +use crate::backends::dummy::DummyBackend; use crate::backends::xorg::{XorgBackend, XorgBackendError}; use crate::client::Clients; use crate::clientmem::ClientMemError; @@ -26,6 +27,7 @@ use crate::render::RenderError; use crate::sighand::SighandError; use crate::state::State; use crate::tree::{DisplayNode, NodeIds}; +use crate::utils::clonecell::CloneCell; use crate::utils::errorfmt::ErrorFmt; use crate::utils::numcell::NumCell; use crate::utils::queue::AsyncQueue; @@ -40,8 +42,6 @@ use std::ops::Deref; use std::rc::Rc; use thiserror::Error; use wheel::Wheel; -use crate::backends::dummy::DummyBackend; -use crate::utils::clonecell::CloneCell; #[macro_use] mod macros; @@ -71,6 +71,7 @@ mod servermem; mod sighand; mod state; mod tasks; +mod theme; mod time; mod tree; mod utils; @@ -153,6 +154,8 @@ fn main_() -> Result<(), MainError> { config: Default::default(), mouse_ids: Default::default(), kb_handlers: Default::default(), + theme: Default::default(), + pending_layout: Default::default(), }); forker.install(&state); let backend = XorgBackend::new(&state)?; @@ -161,6 +164,7 @@ fn main_() -> Result<(), MainError> { state.config.set(Some(Rc::new(config))); let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone())); let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone())); + let _do_layout = engine.spawn(tasks::do_layout(state.clone())); let socket_path = Acceptor::install(&state)?; forker.setenv(b"WAYLAND_DISPLAY", socket_path.as_bytes()); el.run()?; diff --git a/src/render/renderer/framebuffer.rs b/src/render/renderer/framebuffer.rs index 25e550f4..70a78c63 100644 --- a/src/render/renderer/framebuffer.rs +++ b/src/render/renderer/framebuffer.rs @@ -33,6 +33,7 @@ impl Framebuffer { let mut renderer = Renderer { ctx: &self.ctx, fb: &self.gl, + state, }; node.render(&mut renderer, 0, 0); if let Some(rect) = cursor_rect { diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index c2743e85..a3b34860 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -15,8 +15,8 @@ use crate::render::sys::{glDisable, glEnable, GL_BLEND}; use crate::render::Texture; use crate::tree::{ ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode, - CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT, }; +use crate::State; use std::ops::Deref; use std::rc::Rc; use std::slice; @@ -33,14 +33,10 @@ fn focus_color(focus: ContainerFocus) -> (f32, f32, f32) { } } -const TITLE_COLOR: (f32, f32, f32) = ((0x46 as f32)/255., (0x04 as f32)/255., (0x17 as f32)/255.); -// const BORDER_COLOR: (f32, f32, f32) = ((0xba as f32)/255., (0x57 as f32)/255., (0x00 as f32)/255.); -const UNDERLINE_COLOR: (f32, f32, f32) = ((0x66 as f32)/255., (0x24 as f32)/255., (0x37 as f32)/255.); -const BORDER_COLOR: (f32, f32, f32) = ((0x36 as f32)/255., (0x00 as f32)/255., (0x07 as f32)/255.); - pub struct Renderer<'a> { pub(super) ctx: &'a RenderContext, pub(super) fb: &'a GlFrameBuffer, + pub(super) state: &'a State, } impl Renderer<'_> { @@ -104,21 +100,22 @@ 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(), CONTAINER_TITLE_HEIGHT - 1).unwrap(); + let title_rect = Rect::new_sized(x, y, container.width.get(), title_height).unwrap(); let underline_rect = - Rect::new_sized(x, y + CONTAINER_TITLE_HEIGHT - 1, container.width.get(), 1).unwrap(); + Rect::new_sized(x, y + title_height, container.width.get(), 1).unwrap(); 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 (r, g, b) = focus_color(ContainerFocus::None); self.fill_boxes(slice::from_ref(&title_rect), r, g, b, 1.0); - let (r, g, b) = BORDER_COLOR; - self.fill_boxes(slice::from_ref(&underline_rect), r, g, b, 1.0); + let c = self.state.theme.border_color.get(); + self.fill_boxes(slice::from_ref(&underline_rect), c.r, c.g, c.b, c.a); for child in container.children.iter() { let focus = child.focus.get(); let (r, g, b) = focus_color(focus); @@ -128,7 +125,7 @@ impl Renderer<'_> { width += 1; } if focus != ContainerFocus::None { - let rect = Rect::new_sized(pos, y, width, CONTAINER_TITLE_HEIGHT).unwrap(); + let rect = Rect::new_sized(pos, y, width, title_height).unwrap(); self.fill_boxes(slice::from_ref(&rect), r, g, b, 1.0); } pos += width as i32; @@ -157,48 +154,50 @@ impl Renderer<'_> { let border_rect = if split == ContainerSplit::Horizontal { Rect::new_sized( x + body.x2(), - y + body.y1() - CONTAINER_TITLE_HEIGHT, - CONTAINER_BORDER, + y + body.y1() - title_height - 1, + border_width, container.height.get(), ) .unwrap() } else { - title_rects.push(Rect::new_sized( - x, - y + body.y2() + CONTAINER_BORDER, - container.width.get(), - CONTAINER_TITLE_HEIGHT - 1, - ).unwrap()); - underline_rects.push(Rect::new_sized( - x, - y + body.y2() + CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT - 1, - container.width.get(), - 1, - ).unwrap()); - Rect::new_sized( - x, - y + body.y2(), - container.width.get(), - CONTAINER_BORDER, - ) - .unwrap() + 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 (r, g, b) = TITLE_COLOR; - self.fill_boxes(&title_rects, r, g, b, 1.0); - let (r, g, b) = UNDERLINE_COLOR; - self.fill_boxes(&underline_rects, r, g, b, 1.0); - let (r, g, b) = BORDER_COLOR; - self.fill_boxes(&border_rects, r, g, b, 1.0); + let c = self.state.theme.title_color.get(); + self.fill_boxes(&title_rects, c.r, c.g, c.b, c.a); + let c = self.state.theme.underline_color.get(); + self.fill_boxes(&underline_rects, c.r, c.g, c.b, c.a); + let c = self.state.theme.border_color.get(); + self.fill_boxes(&border_rects, c.r, c.g, c.b, c.a); } for child in container.children.iter() { let body = child.body.get(); if body.x1() >= cwidth || body.y1() >= cheight { break; } + let body = body.move_(container.abs_x1.get(), container.abs_y1.get()); unsafe { with_scissor(&body, || { let content = child.content.get(); @@ -323,7 +322,6 @@ impl Renderer<'_> { } pub fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) { - log::info!("rendering at {}x{}", x, y); if let Some(child) = floating.child.get() { child.render(self, x, y) } diff --git a/src/state.rs b/src/state.rs index bfa6b9e3..38f1c10c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,5 +1,8 @@ use crate::async_engine::{AsyncEngine, SpawnedFuture}; -use crate::backend::{Backend, BackendEvent, Keyboard, KeyboardId, KeyboardIds, MouseId, MouseIds, OutputId, OutputIds}; +use crate::backend::{ + Backend, BackendEvent, Keyboard, KeyboardId, KeyboardIds, MouseId, MouseIds, OutputId, + OutputIds, +}; use crate::client::{Client, Clients}; use crate::config::ConfigProxy; use crate::cursor::ServerCursors; @@ -10,7 +13,8 @@ use crate::ifs::wl_output::WlOutputGlobal; use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal}; use crate::ifs::wl_surface::NoneSurfaceExt; use crate::render::RenderContext; -use crate::tree::{DisplayNode, NodeIds}; +use crate::theme::Theme; +use crate::tree::{DisplayNode, Node, NodeIds}; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::linkedlist::LinkedList; @@ -51,6 +55,8 @@ pub struct State { pub none_surface_ext: Rc, pub tree_changed_sent: Cell, pub config: CloneCell>>, + pub theme: Theme, + pub pending_layout: AsyncQueue>, } pub struct MouseData { diff --git a/src/tasks/device.rs b/src/tasks/device.rs index 7177a972..b7a6dd6b 100644 --- a/src/tasks/device.rs +++ b/src/tasks/device.rs @@ -39,7 +39,12 @@ impl DeviceApi for dyn Keyboard { self.removed() } - fn add(self: &Rc, state: &State, handler: SpawnedFuture<()>, data: Rc) { + fn add( + self: &Rc, + state: &State, + handler: SpawnedFuture<()>, + data: Rc, + ) { state.kb_handlers.borrow_mut().insert( self.id(), KeyboardData { @@ -83,7 +88,12 @@ impl DeviceApi for dyn Mouse { self.removed() } - fn add(self: &Rc, state: &State, handler: SpawnedFuture<()>, data: Rc) { + fn add( + self: &Rc, + state: &State, + handler: SpawnedFuture<()>, + data: Rc, + ) { state.mouse_handlers.borrow_mut().insert( self.id(), MouseData { diff --git a/src/tasks/layout.rs b/src/tasks/layout.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index 4073466a..d6730616 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -17,3 +17,12 @@ pub async fn handle_slow_clients(state: Rc) { let mut sch = SlowClientHandler { state }; sch.handle_events().await; } + +pub async fn do_layout(state: Rc) { + loop { + let node = state.pending_layout.pop().await; + if node.needs_layout() { + node.do_layout(); + } + } +} diff --git a/src/tasks/output.rs b/src/tasks/output.rs index a3939381..c35c99dd 100644 --- a/src/tasks/output.rs +++ b/src/tasks/output.rs @@ -38,6 +38,7 @@ impl OutputHandler { stacked: Default::default(), seat_state: Default::default(), }); + on.workspaces.borrow_mut().push(workspace.clone()); on.workspace.set(Some(workspace)); self.state.root.outputs.set(self.output.id(), on.clone()); self.state.add_global(&global); diff --git a/src/theme.rs b/src/theme.rs new file mode 100644 index 00000000..3194f01f --- /dev/null +++ b/src/theme.rs @@ -0,0 +1,60 @@ +use std::cell::Cell; +use crate::NumCell; + +#[derive(Copy, Clone, Debug)] +pub struct Color { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +fn to_f32(c: u8) -> f32 { + c as f32 / 255 as f32 +} + +impl Color { + pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self { + Self { + r: to_f32(r), + g: to_f32(g), + b: to_f32(b), + a: to_f32(a), + } + } +} + +impl From for Color { + fn from(f: i4config::theme::Color) -> Self { + Self { + r: to_f32(f.r), + g: to_f32(f.g), + b: to_f32(f.b), + a: to_f32(f.a), + } + } +} + +pub struct Theme { + pub background_color: Cell, + pub title_color: Cell, + pub underline_color: Cell, + pub border_color: Cell, + pub title_height: Cell, + pub border_width: Cell, + pub version: NumCell, +} + +impl Default for Theme { + fn default() -> Self { + Self { + background_color: Cell::new(Color::from_rgba(0, 0, 0, 255)), + title_color: Cell::new(Color::from_rgba(0x46, 0x04, 0x17, 255)), + underline_color: Cell::new(Color::from_rgba(0x66, 0x24, 0x37, 255)), + border_color: Cell::new(Color::from_rgba(0x36, 0x00, 0x07, 255)), + title_height: Cell::new(17), + border_width: Cell::new(4), + version: NumCell::new(1), + } + } +} diff --git a/src/tree/container.rs b/src/tree/container.rs index 32c7baea..d58dab22 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1,10 +1,10 @@ -use crate::backend::KeyState; +use crate::backend::{KeyState}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT}; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; +use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef}; use crate::{NumCell, State}; @@ -51,9 +51,6 @@ pub enum ContainerFocus { tree_id!(ContainerNodeId); -pub const CONTAINER_TITLE_HEIGHT: i32 = 18; -pub const CONTAINER_BORDER: i32 = 4; - pub struct ContainerNode { pub id: ContainerNodeId, pub parent: CloneCell>, @@ -67,12 +64,16 @@ pub struct ContainerNode { pub height: Cell, pub content_width: Cell, pub content_height: Cell, + pub sum_factors: Cell, + pub theme_version: Cell, + pub needs_layout: Cell, num_children: NumCell, pub children: LinkedList, child_nodes: RefCell>>, seat_state: NodeSeatState, workspace: CloneCell>, seats: RefCell>, + state: Rc, } impl Debug for ContainerNode { @@ -116,10 +117,11 @@ impl ContainerChild { impl ContainerNode { pub fn new( - state: &State, + state: &Rc, workspace: &Rc, parent: Rc, child: Rc, + split: ContainerSplit, ) -> Self { child.clone().set_workspace(workspace); let children = LinkedList::new(); @@ -137,7 +139,7 @@ impl ContainerNode { Self { id: state.node_ids.next(), parent: CloneCell::new(parent), - split: Cell::new(ContainerSplit::Horizontal), + split: Cell::new(split), mono_child: CloneCell::new(None), mono_body: Cell::new(Default::default()), mono_content: Cell::new(Default::default()), @@ -147,12 +149,16 @@ impl ContainerNode { height: Cell::new(0), content_width: Cell::new(0), content_height: Cell::new(0), + sum_factors: Cell::new(1.0), + theme_version: Cell::new(0), + needs_layout: Cell::new(false), num_children: NumCell::new(1), children, child_nodes: RefCell::new(child_nodes), seat_state: Default::default(), workspace: CloneCell::new(workspace.clone()), seats: RefCell::new(Default::default()), + state: state.clone(), } } @@ -226,7 +232,19 @@ impl ContainerNode { } } - fn apply_factors(&self, sum_factors: f64) { + fn apply_factors(self: &Rc, sum_factors: f64) { + self.sum_factors.set(sum_factors); + self.needs_layout.set(true); + self.state.pending_layout.push(self.clone()); + } + + fn do_apply_factors(&self) { + if self.theme_version.get() != self.state.theme.version.get() { + self.update_content_size(); + } + 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(); let split = self.split.get(); let (content_size, other_content_size) = match split { ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()), @@ -243,20 +261,15 @@ impl ContainerNode { remaining_content_size -= body_size; let (x1, y1, width, height) = match split { ContainerSplit::Horizontal => { - (pos, CONTAINER_TITLE_HEIGHT, body_size, other_content_size) + (pos, title_height + 1, body_size, other_content_size) } - _ => ( - 0, - pos + CONTAINER_TITLE_HEIGHT, - other_content_size, - body_size, - ), + _ => (0, pos + title_height + 1, other_content_size, body_size), }; let body = Rect::new_sized(x1, y1, width, height).unwrap(); child.body.set(body); - pos += body_size + CONTAINER_BORDER; + pos += body_size + border_width; if split == ContainerSplit::Vertical { - pos += CONTAINER_TITLE_HEIGHT; + pos += title_height + 1; } } if remaining_content_size > 0 { @@ -273,13 +286,7 @@ impl ContainerNode { let (x1, y1, width, height, size) = match split { ContainerSplit::Horizontal => { let width = body.width() + add; - ( - pos, - CONTAINER_TITLE_HEIGHT, - width, - other_content_size, - width, - ) + (pos, title_height + 1, width, other_content_size, width) } _ => { let height = body.height() + add; @@ -288,12 +295,14 @@ impl ContainerNode { }; body = Rect::new_sized(x1, y1, width, height).unwrap(); child.body.set(body); - pos += size + CONTAINER_BORDER; + pos += size + border_width; if split == ContainerSplit::Vertical { - pos += CONTAINER_TITLE_HEIGHT; + pos += title_height + 1; } } } + self.sum_factors.set(1.0); + self.needs_layout.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); @@ -302,29 +311,32 @@ impl ContainerNode { } fn update_content_size(&self) { + let border_width = self.state.theme.border_width.get(); + let title_height = self.state.theme.title_height.get(); let nc = self.num_children.get(); match self.split.get() { ContainerSplit::Horizontal => { let new_content_size = self .width .get() - .saturating_sub((nc - 1) as i32 * CONTAINER_BORDER); + .saturating_sub((nc - 1) as i32 * border_width); self.content_width.set(new_content_size); self.content_height - .set(self.height.get().saturating_sub(CONTAINER_TITLE_HEIGHT)); + .set(self.height.get().saturating_sub(title_height + 1)); } ContainerSplit::Vertical => { let new_content_size = self.height.get().saturating_sub( - CONTAINER_TITLE_HEIGHT - + (nc - 1) as i32 * (CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT), + title_height + 1 + (nc - 1) as i32 * (border_width + title_height + 1), ); self.content_height.set(new_content_size); self.content_width.set(self.width.get()); } } + self.theme_version.set(self.state.theme.version.get()); } - fn pointer_move(&self, seat: &Rc, x: i32, y: i32) { + fn pointer_move(self: &Rc, seat: &Rc, mut x: i32, mut y: i32) { + let title_height = self.state.theme.title_height.get(); let mut seats = self.seats.borrow_mut(); let seat_state = seats.entry(seat.id()).or_insert_with(|| SeatState { cursor: KnownCursor::Default, @@ -350,9 +362,7 @@ impl ContainerNode { let (prev_factor, child_factor) = match self.split.get() { ContainerSplit::Horizontal => { let cw = self.content_width.get(); - if prev_body.x1() + dist_left > x || x + dist_right > child_body.x2() { - return; - } + x = x.max(prev_body.x1() + dist_left).min(child_body.x2() - dist_right); let prev_factor = (x - prev_body.x1() - dist_left) as f64 / cw as f64; let child_factor = (child_body.x2() - x - dist_right) as f64 / cw as f64; @@ -360,16 +370,14 @@ impl ContainerNode { } ContainerSplit::Vertical => { let ch = self.content_height.get(); - if prev_body.y1() + dist_left > y || y + dist_right > child_body.y2() { - return; - } + y = y.max(prev_body.y1() + dist_left).min(child_body.y2() - dist_right); let prev_factor = (y - prev_body.y1() - dist_left) as f64 / ch as f64; let child_factor = (child_body.y2() - y - dist_right) as f64 / ch as f64; (prev_factor, child_factor) } }; - let sum_factors = 1.0 - prev.factor.get() - op.child.factor.get() + let sum_factors = self.sum_factors.get() - prev.factor.get() - op.child.factor.get() + prev_factor + child_factor; prev.factor.set(prev_factor); @@ -382,7 +390,7 @@ impl ContainerNode { let new_cursor = if self.mono_child.get().is_some() { KnownCursor::Default } else if self.split.get() == ContainerSplit::Horizontal { - if y < CONTAINER_TITLE_HEIGHT { + if y < title_height + 1 { KnownCursor::Default } else { KnownCursor::ResizeLeftRight @@ -392,7 +400,7 @@ impl ContainerNode { for child in self.children.iter() { let body = child.body.get(); if body.y1() > y { - if body.y1() - y > CONTAINER_TITLE_HEIGHT { + if body.y1() - y > title_height + 1 { cursor = KnownCursor::ResizeTopBottom } break; @@ -440,14 +448,22 @@ impl Node for ContainerNode { self.seat_state.destroy_node(self); } + fn needs_layout(&self) -> bool { + self.needs_layout.get() + } + + fn do_layout(&self) { + self.do_apply_factors(); + } + fn get_split(&self) -> Option { Some(self.split.get()) } - fn set_split(&self, split: ContainerSplit) { + fn set_split(self: Rc, split: ContainerSplit) { self.split.set(split); self.update_content_size(); - self.apply_factors(1.0); + self.apply_factors(self.sum_factors.get()); } fn do_focus(self: Rc, seat: &Rc, direction: Direction) { @@ -519,6 +535,7 @@ impl Node for ContainerNode { if button != BTN_LEFT { return; } + let title_height = self.state.theme.title_height.get(); let mut seat_datas = self.seats.borrow_mut(); let seat_data = match seat_datas.get_mut(&seat.id()) { Some(s) => s, @@ -562,7 +579,7 @@ impl Node for ContainerNode { for child in self.children.iter() { let body = child.body.get(); if seat_data.y < body.y1() { - let op = if seat_data.y < body.y1() - CONTAINER_TITLE_HEIGHT { + let op = if seat_data.y < body.y1() - title_height - 1 { SeatOpKind::Resize { dist_left: seat_data.y - child.prev().unwrap().body.get().y2(), dist_right: body.y1() - seat_data.y, @@ -611,7 +628,25 @@ impl Node for ContainerNode { FindTreeResult::AcceptsInput } - fn remove_child(&self, child: &dyn Node) { + fn replace_child(&self, old: &dyn Node, new: Rc) { + let node = match self.child_nodes.borrow_mut().remove(&old.id()) { + Some(c) => c, + None => return, + }; + let link= node.append(ContainerChild { + node: new.clone(), + body: Cell::new(node.body.get()), + content: Cell::new(node.content.get()), + factor: Cell::new(node.factor.get()), + focus: Cell::new(node.focus.get()), + }); + self.child_nodes.borrow_mut().insert(new.id(), link); + new.clone().set_workspace(&self.workspace.get()); + let body = node.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); + new.clone().change_extents(&body); + } + + fn remove_child(self: Rc, child: &dyn Node) { let node = match self.child_nodes.borrow_mut().remove(&child.id()) { Some(c) => c.to_ref(), None => return, @@ -619,7 +654,7 @@ impl Node for ContainerNode { let num_children = self.num_children.fetch_sub(1) - 1; if num_children == 0 { self.seats.borrow_mut().clear(); - self.parent.get().remove_child(self); + self.parent.get().remove_child(&*self); return; } self.update_content_size(); @@ -670,7 +705,7 @@ impl Node for ContainerNode { } } - fn motion(&self, seat: &Rc, x: Fixed, y: Fixed) { + fn motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { self.pointer_move(seat, x.round_down(), y.round_down()); } @@ -690,8 +725,9 @@ impl Node for ContainerNode { size_changed |= self.height.replace(rect.height()) != rect.height(); if size_changed { self.update_content_size(); - self.apply_factors(1.0); + self.do_apply_factors(); self.cancel_seat_ops(); + self.parent.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()); diff --git a/src/tree/mod.rs b/src/tree/mod.rs index e25f8347..d6a45b8e 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -67,6 +67,14 @@ pub trait Node { fn seat_state(&self) -> &NodeSeatState; fn destroy_node(&self, detach: bool); + fn needs_layout(&self) -> bool { + false + } + + fn do_layout(&self) { + // nothing + } + fn get_parent_split(&self) -> Option { None } @@ -79,7 +87,11 @@ pub trait Node { None } - fn set_split(&self, split: ContainerSplit) { + fn set_split(self: Rc, split: ContainerSplit) { + let _ = split; + } + + fn create_split(self: Rc, split: ContainerSplit) { let _ = split; } @@ -154,7 +166,12 @@ pub trait Node { FindTreeResult::Other } - fn remove_child(&self, child: &dyn Node) { + fn replace_child(&self, old: &dyn Node, new: Rc) { + let _ = old; + let _ = new; + } + + fn remove_child(self: Rc, child: &dyn Node) { let _ = child; } @@ -180,7 +197,7 @@ pub trait Node { let _ = seat; } - fn motion(&self, seat: &Rc, x: Fixed, y: Fixed) { + fn motion(self: Rc, seat: &Rc, x: Fixed, y: Fixed) { let _ = seat; let _ = x; let _ = y; @@ -258,6 +275,7 @@ pub struct DisplayNode { pub outputs: CopyHashMap>, pub stacked: LinkedList>, pub seat_state: NodeSeatState, + pub needs_layout: Cell, } impl DisplayNode { @@ -267,6 +285,7 @@ impl DisplayNode { outputs: Default::default(), stacked: Default::default(), seat_state: Default::default(), + needs_layout: Cell::new(false), } } } @@ -292,6 +311,18 @@ impl Node for DisplayNode { self.seat_state.destroy_node(self); } + fn needs_layout(&self) -> bool { + self.needs_layout.get() + } + + fn do_layout(&self) { + self.needs_layout.set(false); + let outputs = self.outputs.lock(); + for output in outputs.values() { + output.do_layout(); + } + } + fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { for stacked in self.stacked.rev_iter() { let ext = stacked.absolute_position(); @@ -365,7 +396,7 @@ impl Node for OutputNode { fn destroy_node(&self, detach: bool) { if detach { - self.display.remove_child(self); + self.display.clone().remove_child(self); } let mut workspaces = self.workspaces.borrow_mut(); for workspace in workspaces.drain(..) { @@ -374,6 +405,13 @@ impl Node for OutputNode { self.seat_state.destroy_node(self); } + fn do_layout(&self) { + let workspaces = self.workspaces.borrow_mut(); + for ws in workspaces.deref() { + ws.do_layout(); + } + } + fn absolute_position(&self) -> Rect { self.position.get() } @@ -390,7 +428,7 @@ impl Node for OutputNode { FindTreeResult::AcceptsInput } - fn remove_child(&self, _child: &dyn Node) { + fn remove_child(self: Rc, _child: &dyn Node) { self.workspace.set(None); } @@ -464,7 +502,7 @@ impl Node for FloatNode { child.find_tree_at(x, y, tree) } - fn remove_child(&self, _child: &dyn Node) { + fn remove_child(self: Rc, _child: &dyn Node) { self.child.set(None); self.display_link.set(None); self.workspace_link.set(None); diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index e32e8086..09ab44cb 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -47,6 +47,15 @@ impl Node for WorkspaceNode { self.seat_state.destroy_node(self); } + fn do_layout(&self) { + if let Some(c) = self.container.get() { + c.do_layout(); + } + for s in self.stacked.iter() { + s.do_layout(); + } + } + fn absolute_position(&self) -> Rect { self.output.get().position.get() } @@ -63,7 +72,7 @@ impl Node for WorkspaceNode { FindTreeResult::AcceptsInput } - fn remove_child(&self, _child: &dyn Node) { + fn remove_child(self: Rc, _child: &dyn Node) { self.container.set(None); }