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 = [
"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"

View file

@ -9,3 +9,4 @@ crate-type = ["lib", "cdylib"]
[dependencies]
i4config = { path = "../i4config" }
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::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);
}
}

View file

@ -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 {

View file

@ -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<InputDevice> },
GetTitleHeight { height: i32 },
GetBorderWidth { width: i32 },
}
#[derive(Encode, Decode, Debug)]

View file

@ -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<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!(MouseIds, MouseId);
pub trait Backend {
}
pub trait Backend {}
pub trait Output {
fn id(&self) -> OutputId;

View file

@ -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<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 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::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
@ -211,8 +214,7 @@ pub struct XorgBackend {
b: Cell<f32>,
}
impl Backend for XorgBackend {
}
impl Backend for XorgBackend {}
fn get_drm(con: &XcbCon) -> Result<Drm, XorgBackendError> {
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));
}

View file

@ -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<u32>,
) -> 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<Seat>) -> Result<(), GetInputDevicesError> {
fn handle_get_input_devices(&self, seat: Option<Seat>) {
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<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)
}
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()
}

View file

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

View file

@ -618,6 +618,10 @@ impl Node for WlSurface {
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) {
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<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.motion_surface(self, x, y)
fn motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
seat.motion_surface(&*self, x, y)
}
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {

View file

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

View file

@ -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<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) {
let pn = match self.parent_node.get() {
Some(pn) => pn,

View file

@ -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()?;

View file

@ -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 {

View file

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

View file

@ -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<NoneSurfaceExt>,
pub tree_changed_sent: Cell<bool>,
pub config: CloneCell<Option<Rc<ConfigProxy>>>,
pub theme: Theme,
pub pending_layout: AsyncQueue<Rc<dyn Node>>,
}
pub struct MouseData {

View file

@ -39,7 +39,12 @@ impl DeviceApi for dyn Keyboard {
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(
self.id(),
KeyboardData {
@ -83,7 +88,12 @@ impl DeviceApi for dyn Mouse {
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(
self.id(),
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 };
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(),
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);

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::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<Rc<dyn Node>>,
@ -67,12 +64,16 @@ pub struct ContainerNode {
pub height: Cell<i32>,
pub content_width: 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>,
pub children: LinkedList<ContainerChild>,
child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>,
seat_state: NodeSeatState,
workspace: CloneCell<Rc<WorkspaceNode>>,
seats: RefCell<AHashMap<SeatId, SeatState>>,
state: Rc<State>,
}
impl Debug for ContainerNode {
@ -116,10 +117,11 @@ impl ContainerChild {
impl ContainerNode {
pub fn new(
state: &State,
state: &Rc<State>,
workspace: &Rc<WorkspaceNode>,
parent: Rc<dyn Node>,
child: Rc<dyn Node>,
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<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 (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<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 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<ContainerSplit> {
Some(self.split.get())
}
fn set_split(&self, split: ContainerSplit) {
fn set_split(self: Rc<Self>, 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<Self>, seat: &Rc<WlSeatGlobal>, 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<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()) {
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<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());
}
@ -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());

View file

@ -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<ContainerSplit> {
None
}
@ -79,7 +87,11 @@ pub trait Node {
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;
}
@ -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<dyn Node>) {
let _ = old;
let _ = new;
}
fn remove_child(self: Rc<Self>, child: &dyn Node) {
let _ = child;
}
@ -180,7 +197,7 @@ pub trait Node {
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 _ = x;
let _ = y;
@ -258,6 +275,7 @@ pub struct DisplayNode {
pub outputs: CopyHashMap<OutputId, Rc<OutputNode>>,
pub stacked: LinkedList<Rc<dyn Node>>,
pub seat_state: NodeSeatState,
pub needs_layout: Cell<bool>,
}
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<FoundNode>) -> 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<Self>, _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<Self>, _child: &dyn Node) {
self.child.set(None);
self.display_link.set(None);
self.workspace_link.set(None);

View file

@ -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<Self>, _child: &dyn Node) {
self.container.set(None);
}