1
0
Fork 0
forked from wry/wry

autocommit 2022-02-17 19:12:52 CET

This commit is contained in:
Julian Orth 2022-02-17 19:12:52 +01:00
parent cf322f05be
commit 195a92d98b
29 changed files with 610 additions and 175 deletions

15
Cargo.lock generated
View file

@ -153,6 +153,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"i4config", "i4config",
"log", "log",
"rand",
] ]
[[package]] [[package]]
@ -474,14 +475,13 @@ dependencies = [
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha", "rand_chacha",
"rand_core", "rand_core",
"rand_hc",
] ]
[[package]] [[package]]
@ -503,15 +503,6 @@ dependencies = [
"getrandom", "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]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.4"

View file

@ -9,3 +9,4 @@ crate-type = ["lib", "cdylib"]
[dependencies] [dependencies]
i4config = { path = "../i4config" } i4config = { path = "../i4config" }
log = "0.4.14" log = "0.4.14"
rand = "0.8.5"

View file

@ -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::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; 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_l, move || change_rate(-1));
s.bind(CTRL | SHIFT | SYM_r, 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_h, move || s.focus(Left));
s.bind(MOD | SYM_j, move || s.focus(Down)); s.bind(MOD | SYM_j, move || s.focus(Down));
s.bind(MOD | SYM_k, move || s.focus(Up)); s.bind(MOD | SYM_k, move || s.focus(Up));
s.bind(MOD | SYM_l, move || s.focus(Right)); 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.bind(MOD | SYM_t, move || {
s.set_split(s.split().other()); s.set_split(s.split().other());
}); });
@ -39,7 +61,11 @@ fn configure_seat(s: Seat) {
fn do_grab(s: Seat, grab: bool) { fn do_grab(s: Seat, grab: bool) {
for device in s.input_devices() { for device in s.input_devices() {
if let InputDevice::Keyboard(kb) = device { 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); grab_keyboard(kb, grab);
} }
} }

View file

@ -1,6 +1,7 @@
use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage}; use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage};
use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION}; use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION};
use crate::keyboard::keymap::Keymap; use crate::keyboard::keymap::Keymap;
use crate::theme::Color;
use crate::{Axis, Command, Direction, InputDevice, Keyboard, LogLevel, ModifiedKeySym, Seat}; use crate::{Axis, Command, Direction, InputDevice, Keyboard, LogLevel, ModifiedKeySym, Seat};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry; 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) { pub fn set_split(&self, seat: Seat, axis: Axis) {
self.send(&ClientMessage::SetSplit { seat, 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 { pub fn create_seat(&self, name: &str) -> Seat {
let response = self.with_response(|| self.send(&ClientMessage::CreateSeat { name })); let response = self.with_response(|| self.send(&ClientMessage::CreateSeat { name }));
match response { match response {

View file

@ -1,6 +1,7 @@
use crate::keyboard::keymap::Keymap; use crate::keyboard::keymap::Keymap;
use crate::keyboard::mods::Modifiers; use crate::keyboard::mods::Modifiers;
use crate::keyboard::syms::KeySym; use crate::keyboard::syms::KeySym;
use crate::theme::Color;
use crate::{Axis, Direction, InputDevice, Keyboard, LogLevel, Seat}; use crate::{Axis, Direction, InputDevice, Keyboard, LogLevel, Seat};
use bincode::{BorrowDecode, Decode, Encode}; use bincode::{BorrowDecode, Decode, Encode};
@ -94,6 +95,30 @@ pub enum ClientMessage<'a> {
kb: Keyboard, kb: Keyboard,
grab: bool, 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)] #[derive(Encode, Decode, Debug)]
@ -105,6 +130,8 @@ pub enum Response {
ParseKeymap { keymap: Keymap }, ParseKeymap { keymap: Keymap },
CreateSeat { seat: Seat }, CreateSeat { seat: Seat },
GetInputDevices { devices: Vec<InputDevice> }, GetInputDevices { devices: Vec<InputDevice> },
GetTitleHeight { height: i32 },
GetBorderWidth { width: i32 },
} }
#[derive(Encode, Decode, Debug)] #[derive(Encode, Decode, Debug)]

View file

@ -9,8 +9,9 @@ use std::collections::HashMap;
mod macros; mod macros;
#[doc(hidden)] #[doc(hidden)]
pub mod _private; pub mod _private;
pub mod keyboard;
pub mod embedded; pub mod embedded;
pub mod keyboard;
pub mod theme;
#[derive(Encode, Decode, Copy, Clone, Debug)] #[derive(Encode, Decode, Copy, Clone, Debug)]
pub enum LogLevel { pub enum LogLevel {
@ -129,6 +130,10 @@ impl Seat {
(|| res = get!().get_input_devices(Some(self)))(); (|| res = get!().get_input_devices(Some(self)))();
res res
} }
pub fn create_split(self, axis: Axis) {
get!().create_split(self, axis);
}
} }
pub fn get_seats() -> Vec<Seat> { pub fn get_seats() -> Vec<Seat> {

45
i4config/src/theme.rs Normal file
View file

@ -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)
}

View file

@ -6,8 +6,7 @@ linear_ids!(OutputIds, OutputId);
linear_ids!(KeyboardIds, KeyboardId); linear_ids!(KeyboardIds, KeyboardId);
linear_ids!(MouseIds, MouseId); linear_ids!(MouseIds, MouseId);
pub trait Backend { pub trait Backend {}
}
pub trait Output { pub trait Output {
fn id(&self) -> OutputId; fn id(&self) -> OutputId;

View file

@ -1,15 +1,12 @@
use std::rc::Rc;
use crate::backend::Backend; use crate::backend::Backend;
use std::rc::Rc;
pub struct DummyBackend { pub struct DummyBackend {}
}
impl DummyBackend { impl DummyBackend {
pub fn new() -> Rc<Self> { pub fn new() -> Rc<Self> {
Rc::new(Self { }) Rc::new(Self {})
} }
} }
impl Backend for DummyBackend { impl Backend for DummyBackend {}
}

View file

@ -1,2 +1,2 @@
pub mod xorg;
pub mod dummy; pub mod dummy;
pub mod xorg;

View file

@ -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::drm::{Drm, DrmError};
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}; use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
use crate::drm::{ModifiedFormat, INVALID_MODIFIER}; use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
@ -211,8 +214,7 @@ pub struct XorgBackend {
b: Cell<f32>, b: Cell<f32>,
} }
impl Backend for XorgBackend { impl Backend for XorgBackend {}
}
fn get_drm(con: &XcbCon) -> Result<Drm, XorgBackendError> { fn get_drm(con: &XcbCon) -> Result<Drm, XorgBackendError> {
unsafe { unsafe {
@ -1098,7 +1100,9 @@ impl Keyboard for XorgSeat {
0, 0,
ptr::null(), 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) { let res = match con.check(res, err) {
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => {
@ -1110,7 +1114,9 @@ impl Keyboard for XorgSeat {
log::error!("Could not grab device {}: status = {}", self.kb, res.status); log::error!("Could not grab device {}: status = {}", self.kb, res.status);
} }
} else { } 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) { if let Err(e) = con.check_cookie(cookie) {
log::error!("Could not ungrab device {}: {}", self.kb, ErrorFmt(e)); log::error!("Could not ungrab device {}: {}", self.kb, ErrorFmt(e));
} }

View file

@ -1,6 +1,6 @@
use crate::backend::{KeyboardId, MouseId}; use crate::backend::{KeyboardId, MouseId};
use crate::ifs::wl_seat::{SeatId, WlSeatGlobal}; use crate::ifs::wl_seat::{SeatId, WlSeatGlobal};
use crate::state::{DeviceHandlerData}; use crate::state::DeviceHandlerData;
use crate::tree::ContainerSplit; use crate::tree::ContainerSplit;
use crate::utils::copyhashmap::CopyHashMap; use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::debug_fn::debug_fn; use crate::utils::debug_fn::debug_fn;
@ -54,7 +54,7 @@ impl ConfigProxyHandler {
msg: &str, msg: &str,
file: Option<&str>, file: Option<&str>,
line: Option<u32>, line: Option<u32>,
) -> Result<(), LogError> { ) {
let level = match level { let level = match level {
LogLevel::Error => Level::Error, LogLevel::Error => Level::Error,
LogLevel::Warn => Level::Warn, LogLevel::Warn => Level::Warn,
@ -74,10 +74,9 @@ impl ConfigProxyHandler {
Ok(()) Ok(())
}); });
log::log!(level, "{:?}", debug); 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 global_name = self.state.globals.name();
let seat = WlSeatGlobal::new(global_name, name, &self.state); let seat = WlSeatGlobal::new(global_name, name, &self.state);
self.state.globals.add_global(&self.state, &seat); self.state.globals.add_global(&self.state, &seat);
@ -86,7 +85,6 @@ impl ConfigProxyHandler {
seat: Seat(seat.id().raw() as _), seat: Seat(seat.id().raw() as _),
}, },
}); });
Ok(())
} }
fn handle_parse_keymap(&self, keymap: &str) -> Result<(), ParseKeymapError> { fn handle_parse_keymap(&self, keymap: &str) -> Result<(), ParseKeymapError> {
@ -248,7 +246,7 @@ impl ConfigProxyHandler {
Ok(()) Ok(())
} }
fn handle_get_input_devices(&self, seat: Option<Seat>) -> Result<(), GetInputDevicesError> { fn handle_get_input_devices(&self, seat: Option<Seat>) {
let id = seat.map(|s| SeatId::from_raw(s.0 as _)); let id = seat.map(|s| SeatId::from_raw(s.0 as _));
let matches = |dhd: &DeviceHandlerData| { let matches = |dhd: &DeviceHandlerData| {
let id = match id { let id = match id {
@ -280,10 +278,9 @@ impl ConfigProxyHandler {
self.send(&ServerMessage::Response { self.send(&ServerMessage::Response {
response: Response::GetInputDevices { devices: res }, response: Response::GetInputDevices { devices: res },
}); });
Ok(())
} }
fn handle_get_seats(&self) -> Result<(), GetSeatsError> { fn handle_get_seats(&self) {
let seats = { let seats = {
let seats = self.state.globals.seats.lock(); let seats = self.state.globals.seats.lock();
seats seats
@ -294,7 +291,6 @@ impl ConfigProxyHandler {
self.send(&ServerMessage::Response { self.send(&ServerMessage::Response {
response: Response::GetSeats { seats }, response: Response::GetSeats { seats },
}); });
Ok(())
} }
fn handle_run( fn handle_run(
@ -311,16 +307,78 @@ impl ConfigProxyHandler {
Ok(()) Ok(())
} }
fn handle_grab( fn handle_grab(&self, kb: Keyboard, grab: bool) -> Result<(), GrabError> {
&self,
kb: Keyboard,
grab: bool,
) -> Result<(), GrabError> {
let kb = self.get_kb(kb)?; let kb = self.get_kb(kb)?;
kb.grab(grab); kb.grab(grab);
Ok(()) 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]) { pub fn handle_request(&self, msg: &[u8]) {
if let Err(e) = self.handle_request_(msg) { if let Err(e) = self.handle_request_(msg) {
log::error!("Could not handle client request: {}", ErrorFmt(e)); log::error!("Could not handle client request: {}", ErrorFmt(e));
@ -339,8 +397,8 @@ impl ConfigProxyHandler {
msg, msg,
file, file,
line, line,
} => self.handle_log_request(level, msg, file, line)?, } => self.handle_log_request(level, msg, file, line),
ClientMessage::CreateSeat { name } => self.handle_create_seat(name)?, ClientMessage::CreateSeat { name } => self.handle_create_seat(name),
ClientMessage::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?, ClientMessage::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?,
ClientMessage::SeatSetKeymap { seat, keymap } => { ClientMessage::SeatSetKeymap { seat, keymap } => {
self.handle_set_keymap(seat, keymap)? self.handle_set_keymap(seat, keymap)?
@ -360,11 +418,22 @@ impl ConfigProxyHandler {
} }
ClientMessage::Focus { seat, direction } => self.handle_focus(seat, direction)?, ClientMessage::Focus { seat, direction } => self.handle_focus(seat, direction)?,
ClientMessage::Move { seat, direction } => {} ClientMessage::Move { seat, direction } => {}
ClientMessage::GetInputDevices { seat } => self.handle_get_input_devices(seat)?, ClientMessage::GetInputDevices { seat } => self.handle_get_input_devices(seat),
ClientMessage::GetSeats => self.handle_get_seats()?, ClientMessage::GetSeats => self.handle_get_seats(),
ClientMessage::RemoveSeat { .. } => {} ClientMessage::RemoveSeat { .. } => {}
ClientMessage::Run { prog, args, env } => self.handle_run(prog, args, env)?, ClientMessage::Run { prog, args, env } => self.handle_run(prog, args, env)?,
ClientMessage::GrabKb { kb, grab } => self.handle_grab(kb, grab)?, 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(()) Ok(())
} }
@ -372,10 +441,6 @@ impl ConfigProxyHandler {
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum CphError { 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")] #[error("Could not process a `parse_keymap` request")]
ParseKeymapError(#[from] ParseKeymapError), ParseKeymapError(#[from] ParseKeymapError),
#[error("Could not process a `set_seat` request")] #[error("Could not process a `set_seat` request")]
@ -384,10 +449,6 @@ enum CphError {
AddShortcutError(#[from] AddShortcutError), AddShortcutError(#[from] AddShortcutError),
#[error("Could not process a `remove_shortcut` request")] #[error("Could not process a `remove_shortcut` request")]
RemoveShortcutError(#[from] RemoveShortcutError), 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")] #[error("Could not process a `set_keymap` request")]
SeatSetKeymapError(#[from] SeatSetKeymapError), SeatSetKeymapError(#[from] SeatSetKeymapError),
#[error("Could not process a `get_repeat_rate` request")] #[error("Could not process a `get_repeat_rate` request")]
@ -404,6 +465,12 @@ enum CphError {
RunError(#[from] RunError), RunError(#[from] RunError),
#[error("Could not process a `grab` request")] #[error("Could not process a `grab` request")]
GrabError(#[from] GrabError), 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")] #[error("Device {0:?} does not exist")]
DeviceDoesNotExist(InputDevice), DeviceDoesNotExist(InputDevice),
#[error("Device {0:?} does not exist")] #[error("Device {0:?} does not exist")]
@ -416,12 +483,6 @@ enum CphError {
ParsingFailed(#[source] DecodeError), ParsingFailed(#[source] DecodeError),
} }
#[derive(Debug, Error)]
enum LogError {}
#[derive(Debug, Error)]
enum CreateSeatError {}
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum ParseKeymapError { enum ParseKeymapError {
#[error("Parsing failed")] #[error("Parsing failed")]
@ -449,12 +510,6 @@ enum RemoveShortcutError {
} }
efrom!(RemoveShortcutError, CphError); efrom!(RemoveShortcutError, CphError);
#[derive(Debug, Error)]
enum GetInputDevicesError {}
#[derive(Debug, Error)]
enum GetSeatsError {}
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum SeatSetKeymapError { enum SeatSetKeymapError {
#[error(transparent)] #[error(transparent)]
@ -513,3 +568,26 @@ enum GrabError {
CphError(#[from] Box<CphError>), CphError(#[from] Box<CphError>),
} }
efrom!(GrabError, CphError); 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<CphError>),
}
efrom!(CreateSplitError, CphError);

View file

@ -195,6 +195,10 @@ impl WlSeatGlobal {
self.keyboard_node.get().set_parent_split(axis) 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) { pub fn get_rate(&self) -> (i32, i32) {
self.repeat_rate.get() self.repeat_rate.get()
} }

View file

@ -147,7 +147,7 @@ impl PointerOwner for DefaultPointerOwner {
} }
if (stack.len(), found_tree.len()) == (divergence, divergence) { if (stack.len(), found_tree.len()) == (divergence, divergence) {
if let Some(node) = found_tree.last() { if let Some(node) = found_tree.last() {
node.node node.node.clone()
.motion(seat, x.apply_fract(node.x), y.apply_fract(node.y)); .motion(seat, x.apply_fract(node.x), y.apply_fract(node.y));
} }
} else { } else {
@ -242,7 +242,7 @@ impl PointerOwner for GrabPointerOwner {
let (x, y) = seat.pos.get(); let (x, y) = seat.pos.get();
let pos = self.node.absolute_position(); let pos = self.node.absolute_position();
let (x_int, y_int) = pos.translate(x.round_down(), y.round_down()); 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)); .motion(seat, x.apply_fract(x_int), y.apply_fract(y_int));
} }

View file

@ -618,6 +618,10 @@ impl Node for WlSurface {
self.xdg.get().map(|x| x.set_split(split)); self.xdg.get().map(|x| x.set_split(split));
} }
fn create_split(self: Rc<Self>, split: ContainerSplit) {
self.xdg.get().map(|x| x.create_split(split));
}
fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let xdg = match self.xdg.get() { let xdg = match self.xdg.get() {
Some(x) => x, Some(x) => x,
@ -670,8 +674,8 @@ impl Node for WlSurface {
seat.enter_surface(&self, x, y) seat.enter_surface(&self, x, y)
} }
fn motion(&self, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) { fn motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.motion_surface(self, x, y) seat.motion_surface(&*self, x, y)
} }
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {

View file

@ -83,6 +83,10 @@ pub trait XdgSurfaceExt: Debug {
let _ = split; let _ = split;
} }
fn create_split(self: Rc<Self>, split: ContainerSplit) {
let _ = split;
}
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let _ = seat; let _ = seat;
let _ = direction; let _ = direction;
@ -158,6 +162,10 @@ impl XdgSurface {
self.ext.get().map(|e| e.set_split(split)); 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<WlSeatGlobal>, direction: Direction) { pub fn move_focus(&self, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let ext = match self.ext.get() { let ext = match self.ext.get() {
None => return, None => return,

View file

@ -373,6 +373,7 @@ impl XdgToplevel {
&workspace, &workspace,
workspace.clone(), workspace.clone(),
self.clone(), self.clone(),
ContainerSplit::Horizontal,
)); ));
workspace.set_container(&container); workspace.set_container(&container);
self.parent_node.set(Some(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)); self.parent_node.get().map(|p| p.set_split(split));
} }
fn create_split(self: Rc<Self>, 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<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
let pn = match self.parent_node.get() { let pn = match self.parent_node.get() {
Some(pn) => pn, Some(pn) => pn,

View file

@ -9,6 +9,7 @@
use crate::acceptor::AcceptorError; use crate::acceptor::AcceptorError;
use crate::async_engine::AsyncError; use crate::async_engine::AsyncError;
use crate::backends::dummy::DummyBackend;
use crate::backends::xorg::{XorgBackend, XorgBackendError}; use crate::backends::xorg::{XorgBackend, XorgBackendError};
use crate::client::Clients; use crate::client::Clients;
use crate::clientmem::ClientMemError; use crate::clientmem::ClientMemError;
@ -26,6 +27,7 @@ use crate::render::RenderError;
use crate::sighand::SighandError; use crate::sighand::SighandError;
use crate::state::State; use crate::state::State;
use crate::tree::{DisplayNode, NodeIds}; use crate::tree::{DisplayNode, NodeIds};
use crate::utils::clonecell::CloneCell;
use crate::utils::errorfmt::ErrorFmt; use crate::utils::errorfmt::ErrorFmt;
use crate::utils::numcell::NumCell; use crate::utils::numcell::NumCell;
use crate::utils::queue::AsyncQueue; use crate::utils::queue::AsyncQueue;
@ -40,8 +42,6 @@ use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use thiserror::Error; use thiserror::Error;
use wheel::Wheel; use wheel::Wheel;
use crate::backends::dummy::DummyBackend;
use crate::utils::clonecell::CloneCell;
#[macro_use] #[macro_use]
mod macros; mod macros;
@ -71,6 +71,7 @@ mod servermem;
mod sighand; mod sighand;
mod state; mod state;
mod tasks; mod tasks;
mod theme;
mod time; mod time;
mod tree; mod tree;
mod utils; mod utils;
@ -153,6 +154,8 @@ fn main_() -> Result<(), MainError> {
config: Default::default(), config: Default::default(),
mouse_ids: Default::default(), mouse_ids: Default::default(),
kb_handlers: Default::default(), kb_handlers: Default::default(),
theme: Default::default(),
pending_layout: Default::default(),
}); });
forker.install(&state); forker.install(&state);
let backend = XorgBackend::new(&state)?; let backend = XorgBackend::new(&state)?;
@ -161,6 +164,7 @@ fn main_() -> Result<(), MainError> {
state.config.set(Some(Rc::new(config))); state.config.set(Some(Rc::new(config)));
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone())); 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 _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)?; let socket_path = Acceptor::install(&state)?;
forker.setenv(b"WAYLAND_DISPLAY", socket_path.as_bytes()); forker.setenv(b"WAYLAND_DISPLAY", socket_path.as_bytes());
el.run()?; el.run()?;

View file

@ -33,6 +33,7 @@ impl Framebuffer {
let mut renderer = Renderer { let mut renderer = Renderer {
ctx: &self.ctx, ctx: &self.ctx,
fb: &self.gl, fb: &self.gl,
state,
}; };
node.render(&mut renderer, 0, 0); node.render(&mut renderer, 0, 0);
if let Some(rect) = cursor_rect { if let Some(rect) = cursor_rect {

View file

@ -15,8 +15,8 @@ use crate::render::sys::{glDisable, glEnable, GL_BLEND};
use crate::render::Texture; use crate::render::Texture;
use crate::tree::{ use crate::tree::{
ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode, ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode,
CONTAINER_BORDER, CONTAINER_TITLE_HEIGHT,
}; };
use crate::State;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use std::slice; 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 struct Renderer<'a> {
pub(super) ctx: &'a RenderContext, pub(super) ctx: &'a RenderContext,
pub(super) fb: &'a GlFrameBuffer, pub(super) fb: &'a GlFrameBuffer,
pub(super) state: &'a State,
} }
impl Renderer<'_> { impl Renderer<'_> {
@ -104,21 +100,22 @@ impl Renderer<'_> {
} }
pub fn render_container(&mut self, container: &ContainerNode, x: i32, y: i32) { 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 cwidth = container.width.get();
let cheight = container.height.get(); let cheight = container.height.get();
let num_children = container.num_children(); let num_children = container.num_children();
let title_rect = let title_rect = Rect::new_sized(x, y, container.width.get(), title_height).unwrap();
Rect::new_sized(x, y, container.width.get(), CONTAINER_TITLE_HEIGHT - 1).unwrap();
let underline_rect = 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() { if let Some(child) = container.mono_child.get() {
let space_per_child = cwidth / num_children as i32; let space_per_child = cwidth / num_children as i32;
let mut rem = cwidth % num_children as i32; let mut rem = cwidth % num_children as i32;
let mut pos = x; let mut pos = x;
let (r, g, b) = focus_color(ContainerFocus::None); let (r, g, b) = focus_color(ContainerFocus::None);
self.fill_boxes(slice::from_ref(&title_rect), r, g, b, 1.0); self.fill_boxes(slice::from_ref(&title_rect), r, g, b, 1.0);
let (r, g, b) = BORDER_COLOR; let c = self.state.theme.border_color.get();
self.fill_boxes(slice::from_ref(&underline_rect), r, g, b, 1.0); self.fill_boxes(slice::from_ref(&underline_rect), c.r, c.g, c.b, c.a);
for child in container.children.iter() { for child in container.children.iter() {
let focus = child.focus.get(); let focus = child.focus.get();
let (r, g, b) = focus_color(focus); let (r, g, b) = focus_color(focus);
@ -128,7 +125,7 @@ impl Renderer<'_> {
width += 1; width += 1;
} }
if focus != ContainerFocus::None { 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); self.fill_boxes(slice::from_ref(&rect), r, g, b, 1.0);
} }
pos += width as i32; pos += width as i32;
@ -157,48 +154,50 @@ impl Renderer<'_> {
let border_rect = if split == ContainerSplit::Horizontal { let border_rect = if split == ContainerSplit::Horizontal {
Rect::new_sized( Rect::new_sized(
x + body.x2(), x + body.x2(),
y + body.y1() - CONTAINER_TITLE_HEIGHT, y + body.y1() - title_height - 1,
CONTAINER_BORDER, border_width,
container.height.get(), container.height.get(),
) )
.unwrap() .unwrap()
} else { } else {
title_rects.push(Rect::new_sized( title_rects.push(
x, Rect::new_sized(
y + body.y2() + CONTAINER_BORDER, x,
container.width.get(), y + body.y2() + border_width,
CONTAINER_TITLE_HEIGHT - 1, container.width.get(),
).unwrap()); title_height,
underline_rects.push(Rect::new_sized( )
x, .unwrap(),
y + body.y2() + CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT - 1, );
container.width.get(), underline_rects.push(
1, Rect::new_sized(
).unwrap()); x,
Rect::new_sized( y + body.y2() + border_width + title_height,
x, container.width.get(),
y + body.y2(), 1,
container.width.get(), )
CONTAINER_BORDER, .unwrap(),
) );
.unwrap() Rect::new_sized(x, y + body.y2(), container.width.get(), border_width)
.unwrap()
}; };
border_rects.push(border_rect); border_rects.push(border_rect);
} }
} }
{ {
let (r, g, b) = TITLE_COLOR; let c = self.state.theme.title_color.get();
self.fill_boxes(&title_rects, r, g, b, 1.0); self.fill_boxes(&title_rects, c.r, c.g, c.b, c.a);
let (r, g, b) = UNDERLINE_COLOR; let c = self.state.theme.underline_color.get();
self.fill_boxes(&underline_rects, r, g, b, 1.0); self.fill_boxes(&underline_rects, c.r, c.g, c.b, c.a);
let (r, g, b) = BORDER_COLOR; let c = self.state.theme.border_color.get();
self.fill_boxes(&border_rects, r, g, b, 1.0); self.fill_boxes(&border_rects, c.r, c.g, c.b, c.a);
} }
for child in container.children.iter() { for child in container.children.iter() {
let body = child.body.get(); let body = child.body.get();
if body.x1() >= cwidth || body.y1() >= cheight { if body.x1() >= cwidth || body.y1() >= cheight {
break; break;
} }
let body = body.move_(container.abs_x1.get(), container.abs_y1.get());
unsafe { unsafe {
with_scissor(&body, || { with_scissor(&body, || {
let content = child.content.get(); let content = child.content.get();
@ -323,7 +322,6 @@ impl Renderer<'_> {
} }
pub fn render_floating(&mut self, floating: &FloatNode, x: i32, y: i32) { 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() { if let Some(child) = floating.child.get() {
child.render(self, x, y) child.render(self, x, y)
} }

View file

@ -1,5 +1,8 @@
use crate::async_engine::{AsyncEngine, SpawnedFuture}; 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::client::{Client, Clients};
use crate::config::ConfigProxy; use crate::config::ConfigProxy;
use crate::cursor::ServerCursors; 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_seat::{SeatIds, WlSeatGlobal};
use crate::ifs::wl_surface::NoneSurfaceExt; use crate::ifs::wl_surface::NoneSurfaceExt;
use crate::render::RenderContext; 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::clonecell::CloneCell;
use crate::utils::copyhashmap::CopyHashMap; use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::linkedlist::LinkedList; use crate::utils::linkedlist::LinkedList;
@ -51,6 +55,8 @@ pub struct State {
pub none_surface_ext: Rc<NoneSurfaceExt>, pub none_surface_ext: Rc<NoneSurfaceExt>,
pub tree_changed_sent: Cell<bool>, pub tree_changed_sent: Cell<bool>,
pub config: CloneCell<Option<Rc<ConfigProxy>>>, pub config: CloneCell<Option<Rc<ConfigProxy>>>,
pub theme: Theme,
pub pending_layout: AsyncQueue<Rc<dyn Node>>,
} }
pub struct MouseData { pub struct MouseData {

View file

@ -39,7 +39,12 @@ impl DeviceApi for dyn Keyboard {
self.removed() self.removed()
} }
fn add(self: &Rc<Self>, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>) { fn add(
self: &Rc<Self>,
state: &State,
handler: SpawnedFuture<()>,
data: Rc<DeviceHandlerData>,
) {
state.kb_handlers.borrow_mut().insert( state.kb_handlers.borrow_mut().insert(
self.id(), self.id(),
KeyboardData { KeyboardData {
@ -83,7 +88,12 @@ impl DeviceApi for dyn Mouse {
self.removed() self.removed()
} }
fn add(self: &Rc<Self>, state: &State, handler: SpawnedFuture<()>, data: Rc<DeviceHandlerData>) { fn add(
self: &Rc<Self>,
state: &State,
handler: SpawnedFuture<()>,
data: Rc<DeviceHandlerData>,
) {
state.mouse_handlers.borrow_mut().insert( state.mouse_handlers.borrow_mut().insert(
self.id(), self.id(),
MouseData { MouseData {

0
src/tasks/layout.rs Normal file
View file

View file

@ -17,3 +17,12 @@ pub async fn handle_slow_clients(state: Rc<State>) {
let mut sch = SlowClientHandler { state }; let mut sch = SlowClientHandler { state };
sch.handle_events().await; sch.handle_events().await;
} }
pub async fn do_layout(state: Rc<State>) {
loop {
let node = state.pending_layout.pop().await;
if node.needs_layout() {
node.do_layout();
}
}
}

View file

@ -38,6 +38,7 @@ impl OutputHandler {
stacked: Default::default(), stacked: Default::default(),
seat_state: Default::default(), seat_state: Default::default(),
}); });
on.workspaces.borrow_mut().push(workspace.clone());
on.workspace.set(Some(workspace)); on.workspace.set(Some(workspace));
self.state.root.outputs.set(self.output.id(), on.clone()); self.state.root.outputs.set(self.output.id(), on.clone());
self.state.add_global(&global); self.state.add_global(&global);

60
src/theme.rs Normal file
View file

@ -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<i4config::theme::Color> 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<Color>,
pub title_color: Cell<Color>,
pub underline_color: Cell<Color>,
pub border_color: Cell<Color>,
pub title_height: Cell<i32>,
pub border_width: Cell<i32>,
pub version: NumCell<u32>,
}
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),
}
}
}

View file

@ -1,10 +1,10 @@
use crate::backend::KeyState; use crate::backend::{KeyState};
use crate::cursor::KnownCursor; use crate::cursor::KnownCursor;
use crate::fixed::Fixed; use crate::fixed::Fixed;
use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT}; use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT};
use crate::rect::Rect; use crate::rect::Rect;
use crate::render::Renderer; 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::clonecell::CloneCell;
use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef}; use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef};
use crate::{NumCell, State}; use crate::{NumCell, State};
@ -51,9 +51,6 @@ pub enum ContainerFocus {
tree_id!(ContainerNodeId); tree_id!(ContainerNodeId);
pub const CONTAINER_TITLE_HEIGHT: i32 = 18;
pub const CONTAINER_BORDER: i32 = 4;
pub struct ContainerNode { pub struct ContainerNode {
pub id: ContainerNodeId, pub id: ContainerNodeId,
pub parent: CloneCell<Rc<dyn Node>>, pub parent: CloneCell<Rc<dyn Node>>,
@ -67,12 +64,16 @@ pub struct ContainerNode {
pub height: Cell<i32>, pub height: Cell<i32>,
pub content_width: Cell<i32>, pub content_width: Cell<i32>,
pub content_height: Cell<i32>, pub content_height: Cell<i32>,
pub sum_factors: Cell<f64>,
pub theme_version: Cell<u32>,
pub needs_layout: Cell<bool>,
num_children: NumCell<usize>, num_children: NumCell<usize>,
pub children: LinkedList<ContainerChild>, pub children: LinkedList<ContainerChild>,
child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>, child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>,
seat_state: NodeSeatState, seat_state: NodeSeatState,
workspace: CloneCell<Rc<WorkspaceNode>>, workspace: CloneCell<Rc<WorkspaceNode>>,
seats: RefCell<AHashMap<SeatId, SeatState>>, seats: RefCell<AHashMap<SeatId, SeatState>>,
state: Rc<State>,
} }
impl Debug for ContainerNode { impl Debug for ContainerNode {
@ -116,10 +117,11 @@ impl ContainerChild {
impl ContainerNode { impl ContainerNode {
pub fn new( pub fn new(
state: &State, state: &Rc<State>,
workspace: &Rc<WorkspaceNode>, workspace: &Rc<WorkspaceNode>,
parent: Rc<dyn Node>, parent: Rc<dyn Node>,
child: Rc<dyn Node>, child: Rc<dyn Node>,
split: ContainerSplit,
) -> Self { ) -> Self {
child.clone().set_workspace(workspace); child.clone().set_workspace(workspace);
let children = LinkedList::new(); let children = LinkedList::new();
@ -137,7 +139,7 @@ impl ContainerNode {
Self { Self {
id: state.node_ids.next(), id: state.node_ids.next(),
parent: CloneCell::new(parent), parent: CloneCell::new(parent),
split: Cell::new(ContainerSplit::Horizontal), split: Cell::new(split),
mono_child: CloneCell::new(None), mono_child: CloneCell::new(None),
mono_body: Cell::new(Default::default()), mono_body: Cell::new(Default::default()),
mono_content: Cell::new(Default::default()), mono_content: Cell::new(Default::default()),
@ -147,12 +149,16 @@ impl ContainerNode {
height: Cell::new(0), height: Cell::new(0),
content_width: Cell::new(0), content_width: Cell::new(0),
content_height: 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), num_children: NumCell::new(1),
children, children,
child_nodes: RefCell::new(child_nodes), child_nodes: RefCell::new(child_nodes),
seat_state: Default::default(), seat_state: Default::default(),
workspace: CloneCell::new(workspace.clone()), workspace: CloneCell::new(workspace.clone()),
seats: RefCell::new(Default::default()), 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<Self>, 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 split = self.split.get();
let (content_size, other_content_size) = match split { let (content_size, other_content_size) = match split {
ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()), ContainerSplit::Horizontal => (self.content_width.get(), self.content_height.get()),
@ -243,20 +261,15 @@ impl ContainerNode {
remaining_content_size -= body_size; remaining_content_size -= body_size;
let (x1, y1, width, height) = match split { let (x1, y1, width, height) = match split {
ContainerSplit::Horizontal => { ContainerSplit::Horizontal => {
(pos, CONTAINER_TITLE_HEIGHT, body_size, other_content_size) (pos, title_height + 1, body_size, other_content_size)
} }
_ => ( _ => (0, pos + title_height + 1, other_content_size, body_size),
0,
pos + CONTAINER_TITLE_HEIGHT,
other_content_size,
body_size,
),
}; };
let body = Rect::new_sized(x1, y1, width, height).unwrap(); let body = Rect::new_sized(x1, y1, width, height).unwrap();
child.body.set(body); child.body.set(body);
pos += body_size + CONTAINER_BORDER; pos += body_size + border_width;
if split == ContainerSplit::Vertical { if split == ContainerSplit::Vertical {
pos += CONTAINER_TITLE_HEIGHT; pos += title_height + 1;
} }
} }
if remaining_content_size > 0 { if remaining_content_size > 0 {
@ -273,13 +286,7 @@ impl ContainerNode {
let (x1, y1, width, height, size) = match split { let (x1, y1, width, height, size) = match split {
ContainerSplit::Horizontal => { ContainerSplit::Horizontal => {
let width = body.width() + add; let width = body.width() + add;
( (pos, title_height + 1, width, other_content_size, width)
pos,
CONTAINER_TITLE_HEIGHT,
width,
other_content_size,
width,
)
} }
_ => { _ => {
let height = body.height() + add; let height = body.height() + add;
@ -288,12 +295,14 @@ impl ContainerNode {
}; };
body = Rect::new_sized(x1, y1, width, height).unwrap(); body = Rect::new_sized(x1, y1, width, height).unwrap();
child.body.set(body); child.body.set(body);
pos += size + CONTAINER_BORDER; pos += size + border_width;
if split == ContainerSplit::Vertical { 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() { for child in self.children.iter() {
let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get());
child.node.clone().change_extents(&body); child.node.clone().change_extents(&body);
@ -302,29 +311,32 @@ impl ContainerNode {
} }
fn update_content_size(&self) { 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(); let nc = self.num_children.get();
match self.split.get() { match self.split.get() {
ContainerSplit::Horizontal => { ContainerSplit::Horizontal => {
let new_content_size = self let new_content_size = self
.width .width
.get() .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_width.set(new_content_size);
self.content_height self.content_height
.set(self.height.get().saturating_sub(CONTAINER_TITLE_HEIGHT)); .set(self.height.get().saturating_sub(title_height + 1));
} }
ContainerSplit::Vertical => { ContainerSplit::Vertical => {
let new_content_size = self.height.get().saturating_sub( let new_content_size = self.height.get().saturating_sub(
CONTAINER_TITLE_HEIGHT title_height + 1 + (nc - 1) as i32 * (border_width + title_height + 1),
+ (nc - 1) as i32 * (CONTAINER_BORDER + CONTAINER_TITLE_HEIGHT),
); );
self.content_height.set(new_content_size); self.content_height.set(new_content_size);
self.content_width.set(self.width.get()); self.content_width.set(self.width.get());
} }
} }
self.theme_version.set(self.state.theme.version.get());
} }
fn pointer_move(&self, seat: &Rc<WlSeatGlobal>, x: i32, y: i32) { fn pointer_move(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, mut x: i32, mut y: i32) {
let title_height = self.state.theme.title_height.get();
let mut seats = self.seats.borrow_mut(); let mut seats = self.seats.borrow_mut();
let seat_state = seats.entry(seat.id()).or_insert_with(|| SeatState { let seat_state = seats.entry(seat.id()).or_insert_with(|| SeatState {
cursor: KnownCursor::Default, cursor: KnownCursor::Default,
@ -350,9 +362,7 @@ impl ContainerNode {
let (prev_factor, child_factor) = match self.split.get() { let (prev_factor, child_factor) = match self.split.get() {
ContainerSplit::Horizontal => { ContainerSplit::Horizontal => {
let cw = self.content_width.get(); let cw = self.content_width.get();
if prev_body.x1() + dist_left > x || x + dist_right > child_body.x2() { x = x.max(prev_body.x1() + dist_left).min(child_body.x2() - dist_right);
return;
}
let prev_factor = (x - prev_body.x1() - dist_left) as f64 / cw as f64; let prev_factor = (x - prev_body.x1() - dist_left) as f64 / cw as f64;
let child_factor = let child_factor =
(child_body.x2() - x - dist_right) as f64 / cw as f64; (child_body.x2() - x - dist_right) as f64 / cw as f64;
@ -360,16 +370,14 @@ impl ContainerNode {
} }
ContainerSplit::Vertical => { ContainerSplit::Vertical => {
let ch = self.content_height.get(); let ch = self.content_height.get();
if prev_body.y1() + dist_left > y || y + dist_right > child_body.y2() { y = y.max(prev_body.y1() + dist_left).min(child_body.y2() - dist_right);
return;
}
let prev_factor = (y - prev_body.y1() - dist_left) as f64 / ch as f64; let prev_factor = (y - prev_body.y1() - dist_left) as f64 / ch as f64;
let child_factor = let child_factor =
(child_body.y2() - y - dist_right) as f64 / ch as f64; (child_body.y2() - y - dist_right) as f64 / ch as f64;
(prev_factor, child_factor) (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 + prev_factor
+ child_factor; + child_factor;
prev.factor.set(prev_factor); prev.factor.set(prev_factor);
@ -382,7 +390,7 @@ impl ContainerNode {
let new_cursor = if self.mono_child.get().is_some() { let new_cursor = if self.mono_child.get().is_some() {
KnownCursor::Default KnownCursor::Default
} else if self.split.get() == ContainerSplit::Horizontal { } else if self.split.get() == ContainerSplit::Horizontal {
if y < CONTAINER_TITLE_HEIGHT { if y < title_height + 1 {
KnownCursor::Default KnownCursor::Default
} else { } else {
KnownCursor::ResizeLeftRight KnownCursor::ResizeLeftRight
@ -392,7 +400,7 @@ impl ContainerNode {
for child in self.children.iter() { for child in self.children.iter() {
let body = child.body.get(); let body = child.body.get();
if body.y1() > y { if body.y1() > y {
if body.y1() - y > CONTAINER_TITLE_HEIGHT { if body.y1() - y > title_height + 1 {
cursor = KnownCursor::ResizeTopBottom cursor = KnownCursor::ResizeTopBottom
} }
break; break;
@ -440,14 +448,22 @@ impl Node for ContainerNode {
self.seat_state.destroy_node(self); 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<ContainerSplit> { fn get_split(&self) -> Option<ContainerSplit> {
Some(self.split.get()) Some(self.split.get())
} }
fn set_split(&self, split: ContainerSplit) { fn set_split(self: Rc<Self>, split: ContainerSplit) {
self.split.set(split); self.split.set(split);
self.update_content_size(); self.update_content_size();
self.apply_factors(1.0); self.apply_factors(self.sum_factors.get());
} }
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) { fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
@ -519,6 +535,7 @@ impl Node for ContainerNode {
if button != BTN_LEFT { if button != BTN_LEFT {
return; return;
} }
let title_height = self.state.theme.title_height.get();
let mut seat_datas = self.seats.borrow_mut(); let mut seat_datas = self.seats.borrow_mut();
let seat_data = match seat_datas.get_mut(&seat.id()) { let seat_data = match seat_datas.get_mut(&seat.id()) {
Some(s) => s, Some(s) => s,
@ -562,7 +579,7 @@ impl Node for ContainerNode {
for child in self.children.iter() { for child in self.children.iter() {
let body = child.body.get(); let body = child.body.get();
if seat_data.y < body.y1() { 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 { SeatOpKind::Resize {
dist_left: seat_data.y - child.prev().unwrap().body.get().y2(), dist_left: seat_data.y - child.prev().unwrap().body.get().y2(),
dist_right: body.y1() - seat_data.y, dist_right: body.y1() - seat_data.y,
@ -611,7 +628,25 @@ impl Node for ContainerNode {
FindTreeResult::AcceptsInput FindTreeResult::AcceptsInput
} }
fn remove_child(&self, child: &dyn Node) { fn replace_child(&self, old: &dyn Node, new: Rc<dyn Node>) {
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<Self>, child: &dyn Node) {
let node = match self.child_nodes.borrow_mut().remove(&child.id()) { let node = match self.child_nodes.borrow_mut().remove(&child.id()) {
Some(c) => c.to_ref(), Some(c) => c.to_ref(),
None => return, None => return,
@ -619,7 +654,7 @@ impl Node for ContainerNode {
let num_children = self.num_children.fetch_sub(1) - 1; let num_children = self.num_children.fetch_sub(1) - 1;
if num_children == 0 { if num_children == 0 {
self.seats.borrow_mut().clear(); self.seats.borrow_mut().clear();
self.parent.get().remove_child(self); self.parent.get().remove_child(&*self);
return; return;
} }
self.update_content_size(); self.update_content_size();
@ -670,7 +705,7 @@ impl Node for ContainerNode {
} }
} }
fn motion(&self, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) { fn motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
self.pointer_move(seat, x.round_down(), y.round_down()); 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(); size_changed |= self.height.replace(rect.height()) != rect.height();
if size_changed { if size_changed {
self.update_content_size(); self.update_content_size();
self.apply_factors(1.0); self.do_apply_factors();
self.cancel_seat_ops(); self.cancel_seat_ops();
self.parent.get().child_size_changed(&*self, rect.width(), rect.height());
} else { } else {
for child in self.children.iter() { for child in self.children.iter() {
let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get()); let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get());

View file

@ -67,6 +67,14 @@ pub trait Node {
fn seat_state(&self) -> &NodeSeatState; fn seat_state(&self) -> &NodeSeatState;
fn destroy_node(&self, detach: bool); fn destroy_node(&self, detach: bool);
fn needs_layout(&self) -> bool {
false
}
fn do_layout(&self) {
// nothing
}
fn get_parent_split(&self) -> Option<ContainerSplit> { fn get_parent_split(&self) -> Option<ContainerSplit> {
None None
} }
@ -79,7 +87,11 @@ pub trait Node {
None None
} }
fn set_split(&self, split: ContainerSplit) { fn set_split(self: Rc<Self>, split: ContainerSplit) {
let _ = split;
}
fn create_split(self: Rc<Self>, split: ContainerSplit) {
let _ = split; let _ = split;
} }
@ -154,7 +166,12 @@ pub trait Node {
FindTreeResult::Other FindTreeResult::Other
} }
fn remove_child(&self, child: &dyn Node) { fn replace_child(&self, old: &dyn Node, new: Rc<dyn Node>) {
let _ = old;
let _ = new;
}
fn remove_child(self: Rc<Self>, child: &dyn Node) {
let _ = child; let _ = child;
} }
@ -180,7 +197,7 @@ pub trait Node {
let _ = seat; let _ = seat;
} }
fn motion(&self, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) { fn motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
let _ = seat; let _ = seat;
let _ = x; let _ = x;
let _ = y; let _ = y;
@ -258,6 +275,7 @@ pub struct DisplayNode {
pub outputs: CopyHashMap<OutputId, Rc<OutputNode>>, pub outputs: CopyHashMap<OutputId, Rc<OutputNode>>,
pub stacked: LinkedList<Rc<dyn Node>>, pub stacked: LinkedList<Rc<dyn Node>>,
pub seat_state: NodeSeatState, pub seat_state: NodeSeatState,
pub needs_layout: Cell<bool>,
} }
impl DisplayNode { impl DisplayNode {
@ -267,6 +285,7 @@ impl DisplayNode {
outputs: Default::default(), outputs: Default::default(),
stacked: Default::default(), stacked: Default::default(),
seat_state: 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); 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<FoundNode>) -> FindTreeResult { fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
for stacked in self.stacked.rev_iter() { for stacked in self.stacked.rev_iter() {
let ext = stacked.absolute_position(); let ext = stacked.absolute_position();
@ -365,7 +396,7 @@ impl Node for OutputNode {
fn destroy_node(&self, detach: bool) { fn destroy_node(&self, detach: bool) {
if detach { if detach {
self.display.remove_child(self); self.display.clone().remove_child(self);
} }
let mut workspaces = self.workspaces.borrow_mut(); let mut workspaces = self.workspaces.borrow_mut();
for workspace in workspaces.drain(..) { for workspace in workspaces.drain(..) {
@ -374,6 +405,13 @@ impl Node for OutputNode {
self.seat_state.destroy_node(self); 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 { fn absolute_position(&self) -> Rect {
self.position.get() self.position.get()
} }
@ -390,7 +428,7 @@ impl Node for OutputNode {
FindTreeResult::AcceptsInput FindTreeResult::AcceptsInput
} }
fn remove_child(&self, _child: &dyn Node) { fn remove_child(self: Rc<Self>, _child: &dyn Node) {
self.workspace.set(None); self.workspace.set(None);
} }
@ -464,7 +502,7 @@ impl Node for FloatNode {
child.find_tree_at(x, y, tree) child.find_tree_at(x, y, tree)
} }
fn remove_child(&self, _child: &dyn Node) { fn remove_child(self: Rc<Self>, _child: &dyn Node) {
self.child.set(None); self.child.set(None);
self.display_link.set(None); self.display_link.set(None);
self.workspace_link.set(None); self.workspace_link.set(None);

View file

@ -47,6 +47,15 @@ impl Node for WorkspaceNode {
self.seat_state.destroy_node(self); 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 { fn absolute_position(&self) -> Rect {
self.output.get().position.get() self.output.get().position.get()
} }
@ -63,7 +72,7 @@ impl Node for WorkspaceNode {
FindTreeResult::AcceptsInput FindTreeResult::AcceptsInput
} }
fn remove_child(&self, _child: &dyn Node) { fn remove_child(self: Rc<Self>, _child: &dyn Node) {
self.container.set(None); self.container.set(None);
} }