autocommit 2022-02-19 19:41:18 CET
This commit is contained in:
parent
bb0468feea
commit
ae66acef73
32 changed files with 880 additions and 164 deletions
236
Cargo.lock
generated
236
Cargo.lock
generated
|
|
@ -77,18 +77,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.0-beta.2"
|
||||
version = "2.0.0-beta.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3b09eea9771bcc3c1d3f21325c51066859dbb9addfad6325273630d9ea1707d"
|
||||
checksum = "d20beb3a5bf7c149e1c9cfe54a53eab9c31e7f00ab74e734e05272c65be4b61f"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.0-beta.2"
|
||||
version = "2.0.0-beta.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebde72585aa64e130b4c1d3612742253e7c486f25cb299b4373e505130519279"
|
||||
checksum = "cb2390a472627bfe18ac250746d32a47d91c4720faacc3d21147298d67063e49"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
|
@ -116,12 +116,45 @@ version = "1.4.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cairo-rs"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b869e97a87170f96762f9f178eae8c461147e722ba21dd8814105bf5716bf14a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cairo-sys-rs",
|
||||
"glib",
|
||||
"libc",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cairo-sys-rs"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "295b6eb918a60a25fec0b23a5e633e74fddbaf7bb04411e65a10c366aca4b5cd"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
|
|
@ -284,6 +317,68 @@ version = "0.26.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41dcfbdb6cc6c02aee163339465d8a40d6f3f64c3a43f729a4195f0e153338b7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-task",
|
||||
"glib-macros",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-macros"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e58b262ff65ef771003873cea8c10e0fe854f1c508d48d62a4111a1ff163f7d1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"proc-macro-crate",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa1d4e1a63d8574541e5b92931e4e669ddc87ffa85d58e84e631dba13ad2e10c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
|
@ -310,6 +405,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"bstr",
|
||||
"byteorder",
|
||||
"cairo-rs",
|
||||
"chrono",
|
||||
"default-config",
|
||||
"env_logger",
|
||||
|
|
@ -321,6 +417,8 @@ dependencies = [
|
|||
"num-derive",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"pango",
|
||||
"pangocairo",
|
||||
"rand",
|
||||
"renderdoc",
|
||||
"repc",
|
||||
|
|
@ -437,6 +535,58 @@ version = "1.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79211eff430c29cc38c69e0ab54bc78fa1568121ca9737707eee7f92a8417a94"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"glib",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pango-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango-sys"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"libc",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pangocairo"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7876a45c1f1d1a75a2601dc6d9ef2cb5a8be0e3d76f909d82450759929035366"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cairo-rs",
|
||||
"glib",
|
||||
"libc",
|
||||
"pango",
|
||||
"pangocairo-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pangocairo-sys"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cf746594916c81d5f739af9335c5f55a1f4606d80b3e1d821f18cf95a29494"
|
||||
dependencies = [
|
||||
"cairo-sys-rs",
|
||||
"glib-sys",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.8"
|
||||
|
|
@ -449,12 +599,52 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dada8c9981fcf32929c3c0f0cd796a9284aca335565227ed88c83babb1d43dc"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
|
|
@ -568,6 +758,12 @@ version = "0.1.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.5"
|
||||
|
|
@ -591,6 +787,19 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
|
|
@ -631,6 +840,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uapi"
|
||||
version = "0.2.7"
|
||||
|
|
@ -663,6 +881,12 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
|
@ -671,9 +895,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.4"
|
||||
version = "0.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0e85ed1066abcc0ea331cce3ce83cccf30ae9900529ca46f353b22ca79b56b8"
|
||||
checksum = "757cfbfe0d17ee6f22fe97e536d463047d451b47cf9d11e2b7d1398b0ef274dd"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
|
|
|
|||
|
|
@ -35,7 +35,10 @@ smallvec = { version = "1.8.0", features = ["const_generics", "const_new", "unio
|
|||
backtrace = "0.3.64"
|
||||
byteorder = "1.4.3"
|
||||
chrono = "0.4.19"
|
||||
bincode = "2.0.0-beta.2"
|
||||
bincode = "2.0.0-beta.3"
|
||||
pangocairo = "0.15.1"
|
||||
cairo-rs = { version = "0.15.1", features = ["png"] }
|
||||
pango = { version = "0.15.2", features = ["v1_44"] }
|
||||
i4config = { path = "i4config" }
|
||||
default-config = { path = "default-config" }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
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_d, SYM_h, SYM_j, SYM_k, SYM_l, SYM_period, SYM_r, SYM_t,
|
||||
SYM_v, SYM_y,
|
||||
SYM_Super_L, SYM_b, SYM_comma, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_period, SYM_r,
|
||||
SYM_t, SYM_v, SYM_y,
|
||||
};
|
||||
use i4config::theme::{get_title_height, set_title_color, set_title_height, Color};
|
||||
use i4config::Axis::{Horizontal, Vertical};
|
||||
|
|
@ -54,6 +54,10 @@ fn configure_seat(s: Seat) {
|
|||
s.set_split(s.split().other());
|
||||
});
|
||||
|
||||
s.bind(MOD | SYM_f, move || {
|
||||
s.focus_parent();
|
||||
});
|
||||
|
||||
s.bind(MOD | SHIFT | SYM_h, move || s.move_(Left));
|
||||
s.bind(MOD | SHIFT | SYM_j, move || s.move_(Down));
|
||||
s.bind(MOD | SHIFT | SYM_k, move || s.move_(Up));
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bincode = "2.0.0-beta.2"
|
||||
bincode = "2.0.0-beta.3"
|
||||
log = "0.4.14"
|
||||
|
|
|
|||
|
|
@ -250,6 +250,10 @@ impl Client {
|
|||
self.send(&ClientMessage::CreateSplit { seat, axis });
|
||||
}
|
||||
|
||||
pub fn focus_parent(&self, seat: Seat) {
|
||||
self.send(&ClientMessage::FocusParent { seat });
|
||||
}
|
||||
|
||||
pub fn create_seat(&self, name: &str) -> Seat {
|
||||
let response = self.with_response(|| self.send(&ClientMessage::CreateSeat { name }));
|
||||
match response {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ pub enum ClientMessage<'a> {
|
|||
seat: Seat,
|
||||
axis: Axis,
|
||||
},
|
||||
FocusParent {
|
||||
seat: Seat,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
|
|
|
|||
|
|
@ -134,6 +134,10 @@ impl Seat {
|
|||
pub fn create_split(self, axis: Axis) {
|
||||
get!().create_split(self, axis);
|
||||
}
|
||||
|
||||
pub fn focus_parent(self) {
|
||||
get!().focus_parent(self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_seats() -> Vec<Seat> {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,14 @@ pub enum AsyncError {
|
|||
EventLoopError(#[from] EventLoopError),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Phase {
|
||||
EventHandling,
|
||||
Layout,
|
||||
PostLayout,
|
||||
}
|
||||
const NUM_PHASES: usize = 3;
|
||||
|
||||
pub struct AsyncEngine {
|
||||
wheel: Rc<Wheel>,
|
||||
el: Rc<EventLoop>,
|
||||
|
|
@ -56,7 +64,15 @@ impl AsyncEngine {
|
|||
}
|
||||
|
||||
pub fn spawn<T, F: Future<Output = T> + 'static>(&self, f: F) -> SpawnedFuture<T> {
|
||||
self.queue.spawn(f)
|
||||
self.queue.spawn(Phase::EventHandling, f)
|
||||
}
|
||||
|
||||
pub fn spawn2<T, F: Future<Output = T> + 'static>(
|
||||
&self,
|
||||
phase: Phase,
|
||||
f: F,
|
||||
) -> SpawnedFuture<T> {
|
||||
self.queue.spawn(phase, f)
|
||||
}
|
||||
|
||||
pub fn fd(self: &Rc<Self>, fd: &Rc<OwnedFd>) -> Result<AsyncFd, AsyncError> {
|
||||
|
|
@ -171,6 +187,7 @@ mod timeout {
|
|||
|
||||
mod task {
|
||||
use crate::async_engine::queue::DispatchQueue;
|
||||
use crate::async_engine::Phase;
|
||||
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
|
||||
use crate::NumCell;
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
|
|
@ -253,6 +270,7 @@ mod task {
|
|||
|
||||
struct Task<T, F: Future<Output = T>> {
|
||||
ref_count: NumCell<u64>,
|
||||
phase: Phase,
|
||||
state: NumCell<u32>,
|
||||
data: UnsafeCell<TaskData<T, F>>,
|
||||
waker: Cell<Option<Waker>>,
|
||||
|
|
@ -282,9 +300,14 @@ mod task {
|
|||
}
|
||||
|
||||
impl DispatchQueue {
|
||||
pub(super) fn spawn<T, F: Future<Output = T>>(self: &Rc<Self>, f: F) -> SpawnedFuture<T> {
|
||||
pub(super) fn spawn<T, F: Future<Output = T>>(
|
||||
self: &Rc<Self>,
|
||||
phase: Phase,
|
||||
f: F,
|
||||
) -> SpawnedFuture<T> {
|
||||
let f = Box::new(Task {
|
||||
ref_count: NumCell::new(1),
|
||||
phase,
|
||||
state: NumCell::new(0),
|
||||
data: UnsafeCell::new(TaskData {
|
||||
future: ManuallyDrop::new(f),
|
||||
|
|
@ -354,10 +377,13 @@ mod task {
|
|||
self.state.or_assign(RUNNING);
|
||||
self.inc_ref_count();
|
||||
let data = self as *const _ as _;
|
||||
self.queue.push(Runnable {
|
||||
data,
|
||||
run: Self::run_proxy,
|
||||
});
|
||||
self.queue.push(
|
||||
Runnable {
|
||||
data,
|
||||
run: Self::run_proxy,
|
||||
},
|
||||
self.phase,
|
||||
);
|
||||
} else {
|
||||
self.state.or_assign(RUN_AGAIN);
|
||||
}
|
||||
|
|
@ -404,13 +430,15 @@ mod task {
|
|||
|
||||
mod queue {
|
||||
use crate::async_engine::task::Runnable;
|
||||
use crate::async_engine::AsyncError;
|
||||
use crate::async_engine::{AsyncError, Phase, NUM_PHASES};
|
||||
use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopId};
|
||||
use crate::utils::array;
|
||||
use crate::utils::numcell::NumCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::VecDeque;
|
||||
use std::error::Error;
|
||||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) struct Dispatcher {
|
||||
|
|
@ -425,7 +453,8 @@ mod queue {
|
|||
id,
|
||||
el: el.clone(),
|
||||
dispatch_scheduled: Cell::new(false),
|
||||
queue: RefCell::new(Default::default()),
|
||||
num_queued: Default::default(),
|
||||
queues: array::from_fn(|_| Default::default()),
|
||||
iteration: Default::default(),
|
||||
});
|
||||
let slf = Rc::new(Dispatcher {
|
||||
|
|
@ -439,15 +468,20 @@ mod queue {
|
|||
|
||||
impl EventLoopDispatcher for Dispatcher {
|
||||
fn dispatch(self: Rc<Self>, _events: i32) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
let mut stash = self.stash.borrow_mut();
|
||||
while self.queue.num_queued.get() > 0 {
|
||||
self.queue.iteration.fetch_add(1);
|
||||
let mut stash = self.stash.borrow_mut();
|
||||
mem::swap(&mut *stash, &mut *self.queue.queue.borrow_mut());
|
||||
if stash.is_empty() {
|
||||
break;
|
||||
}
|
||||
for runnable in stash.drain(..) {
|
||||
runnable.run();
|
||||
let mut phase = 0;
|
||||
while phase < NUM_PHASES as usize {
|
||||
mem::swap(&mut *stash, &mut *self.queue.queues[phase].borrow_mut());
|
||||
if stash.is_empty() {
|
||||
phase += 1;
|
||||
continue;
|
||||
}
|
||||
self.queue.num_queued.fetch_sub(stash.len());
|
||||
for runnable in stash.drain(..) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
self.queue.dispatch_scheduled.set(false);
|
||||
|
|
@ -458,7 +492,9 @@ mod queue {
|
|||
impl Drop for Dispatcher {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.queue.el.remove(self.queue.id);
|
||||
mem::take(&mut *self.queue.queue.borrow_mut());
|
||||
for queue in &self.queue.queues {
|
||||
mem::take(queue.borrow_mut().deref_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -466,13 +502,15 @@ mod queue {
|
|||
dispatch_scheduled: Cell<bool>,
|
||||
id: EventLoopId,
|
||||
el: Rc<EventLoop>,
|
||||
queue: RefCell<VecDeque<Runnable>>,
|
||||
num_queued: NumCell<usize>,
|
||||
queues: [RefCell<VecDeque<Runnable>>; NUM_PHASES],
|
||||
iteration: NumCell<u64>,
|
||||
}
|
||||
|
||||
impl DispatchQueue {
|
||||
pub fn push(&self, runnable: Runnable) {
|
||||
self.queue.borrow_mut().push_back(runnable);
|
||||
pub fn push(&self, runnable: Runnable, phase: Phase) {
|
||||
self.queues[phase as usize].borrow_mut().push_back(runnable);
|
||||
self.num_queued.fetch_add(1);
|
||||
if !self.dispatch_scheduled.get() {
|
||||
let _ = self.el.schedule(self.id);
|
||||
self.dispatch_scheduled.set(true);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::client::{Client, ClientError};
|
|||
use crate::object::ObjectId;
|
||||
use crate::utils::buffd::{BufFdIn, BufFdOut, MsgParser};
|
||||
use crate::utils::vec_ext::VecExt;
|
||||
use crate::ErrorFmt;
|
||||
use crate::{ErrorFmt, Phase};
|
||||
use futures::{select, FutureExt};
|
||||
use std::collections::VecDeque;
|
||||
use std::mem;
|
||||
|
|
@ -12,7 +12,7 @@ pub async fn client(data: Rc<Client>) {
|
|||
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
|
||||
let mut dispatch_fr = data.state.eng.spawn(dispatch_fr(data.clone())).fuse();
|
||||
let mut shutdown = data.shutdown.triggered().fuse();
|
||||
let _send = data.state.eng.spawn(send(data.clone()));
|
||||
let _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone()));
|
||||
select! {
|
||||
_ = recv => { },
|
||||
_ = dispatch_fr => { },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use crate::backend::{KeyboardId, MouseId};
|
||||
use crate::ifs::wl_seat::{SeatId, WlSeatGlobal};
|
||||
use crate::state::DeviceHandlerData;
|
||||
use crate::tree::ContainerSplit;
|
||||
use crate::tree::walker::visit_containers;
|
||||
use crate::tree::{ContainerSplit, Node};
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::debug_fn::debug_fn;
|
||||
use crate::utils::stack::Stack;
|
||||
|
|
@ -335,6 +336,12 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_focus_parent(&self, seat: Seat) -> Result<(), FocusParentError> {
|
||||
let seat = self.get_seat(seat)?;
|
||||
seat.focus_parent();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_title_height(&self, height: i32) -> Result<(), SetTitleHeightError> {
|
||||
if height < 0 {
|
||||
return Err(SetTitleHeightError::Negative(height));
|
||||
|
|
@ -343,9 +350,10 @@ impl ConfigProxyHandler {
|
|||
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());
|
||||
self.state
|
||||
.root
|
||||
.clone()
|
||||
.visit(&mut visit_containers(|c| c.on_theme_changed()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -357,9 +365,10 @@ impl ConfigProxyHandler {
|
|||
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());
|
||||
self.state
|
||||
.root
|
||||
.clone()
|
||||
.visit(&mut visit_containers(|c| c.on_theme_changed()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -434,6 +443,7 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::GetTitleHeight => self.handle_get_title_height(),
|
||||
ClientMessage::GetBorderWidth => self.handle_get_border_width(),
|
||||
ClientMessage::CreateSplit { seat, axis } => self.handle_create_split(seat, axis)?,
|
||||
ClientMessage::FocusParent { seat } => self.handle_focus_parent(seat)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -467,6 +477,8 @@ enum CphError {
|
|||
GrabError(#[from] GrabError),
|
||||
#[error("Could not process a `create_split` request")]
|
||||
CreateSplitError(#[from] CreateSplitError),
|
||||
#[error("Could not process a `focus_parent` request")]
|
||||
FocusParentError(#[from] FocusParentError),
|
||||
#[error("Could not process a `set_title_height` request")]
|
||||
SetTitleHeightError(#[from] SetTitleHeightError),
|
||||
#[error("Could not process a `set_border_width` request")]
|
||||
|
|
@ -591,3 +603,10 @@ enum CreateSplitError {
|
|||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(CreateSplitError, CphError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum FocusParentError {
|
||||
#[error(transparent)]
|
||||
CphError(#[from] Box<CphError>),
|
||||
}
|
||||
efrom!(FocusParentError, CphError);
|
||||
|
|
|
|||
|
|
@ -199,6 +199,10 @@ impl WlSeatGlobal {
|
|||
self.keyboard_node.get().create_split(axis)
|
||||
}
|
||||
|
||||
pub fn focus_parent(self: &Rc<Self>) {
|
||||
self.keyboard_node.get().focus_parent(self);
|
||||
}
|
||||
|
||||
pub fn get_rate(&self) -> (i32, i32) {
|
||||
self.repeat_rate.get()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,12 +212,12 @@ impl WlSeatGlobal {
|
|||
}
|
||||
|
||||
fn focus_xdg_surface(self: &Rc<Self>, xdg: &Rc<XdgSurface>) {
|
||||
self.focus_surface(&xdg.focus_surface(self));
|
||||
self.focus_node(xdg.focus_surface(self));
|
||||
}
|
||||
|
||||
fn focus_surface(self: &Rc<Self>, surface: &Rc<WlSurface>) {
|
||||
pub fn focus_node(self: &Rc<Self>, node: Rc<dyn Node>) {
|
||||
let old = self.keyboard_node.get();
|
||||
if old.id() == surface.node_id {
|
||||
if old.id() == node.id() {
|
||||
return;
|
||||
}
|
||||
old.unfocus(self);
|
||||
|
|
@ -225,36 +225,11 @@ impl WlSeatGlobal {
|
|||
old.active_changed(false);
|
||||
}
|
||||
|
||||
if surface.seat_state().focus(self) {
|
||||
surface.active_changed(true);
|
||||
}
|
||||
surface.clone().focus(self);
|
||||
self.keyboard_node.set(surface.clone());
|
||||
|
||||
let pressed_keys: Vec<_> = self.pressed_keys.borrow().iter().copied().collect();
|
||||
let serial = self.serial.fetch_add(1);
|
||||
self.surface_kb_event(0, &surface, |k| {
|
||||
k.send_enter(serial, surface.id, &pressed_keys)
|
||||
});
|
||||
let ModifierState {
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
} = self.kb_state.borrow().mods();
|
||||
let serial = self.serial.fetch_add(1);
|
||||
self.surface_kb_event(0, &surface, |k| {
|
||||
k.send_modifiers(serial, mods_depressed, mods_latched, mods_locked, group)
|
||||
});
|
||||
|
||||
if old.client_id() != Some(surface.client.id) {
|
||||
self.offer_selection::<WlDataDevice>(&self.selection, &surface.client);
|
||||
self.offer_selection::<ZwpPrimarySelectionDeviceV1>(
|
||||
&self.primary_selection,
|
||||
&surface.client,
|
||||
);
|
||||
if node.seat_state().focus(self) {
|
||||
node.active_changed(true);
|
||||
}
|
||||
node.clone().focus(self);
|
||||
self.keyboard_node.set(node.clone());
|
||||
}
|
||||
|
||||
fn offer_selection<T: ipc::Vtable>(
|
||||
|
|
@ -405,7 +380,7 @@ impl WlSeatGlobal {
|
|||
self.surface_pointer_event(0, surface, |p| p.send_button(serial, 0, button, state));
|
||||
self.surface_pointer_frame(surface);
|
||||
if pressed && surface.belongs_to_toplevel() {
|
||||
self.focus_surface(surface);
|
||||
self.focus_node(surface.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -463,6 +438,36 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
// Focus callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn focus_surface(&self, surface: &WlSurface) {
|
||||
let pressed_keys: Vec<_> = self.pressed_keys.borrow().iter().copied().collect();
|
||||
let serial = self.serial.fetch_add(1);
|
||||
self.surface_kb_event(0, &surface, |k| {
|
||||
k.send_enter(serial, surface.id, &pressed_keys)
|
||||
});
|
||||
let ModifierState {
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
} = self.kb_state.borrow().mods();
|
||||
let serial = self.serial.fetch_add(1);
|
||||
self.surface_kb_event(0, &surface, |k| {
|
||||
k.send_modifiers(serial, mods_depressed, mods_latched, mods_locked, group)
|
||||
});
|
||||
|
||||
if self.keyboard_node.get().client_id() != Some(surface.client.id) {
|
||||
self.offer_selection::<WlDataDevice>(&self.selection, &surface.client);
|
||||
self.offer_selection::<ZwpPrimarySelectionDeviceV1>(
|
||||
&self.primary_selection,
|
||||
&surface.client,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Key callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn key_surface(&self, surface: &WlSurface, key: u32, state: u32) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use crate::object::Object;
|
|||
use crate::pixman::Region;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::walker::NodeVisitor;
|
||||
use crate::tree::{ContainerSplit, Node, NodeId};
|
||||
use crate::utils::buffd::{MsgParser, MsgParserError};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
|
|
@ -578,6 +579,12 @@ dedicated_add_obj!(WlSurface, WlSurfaceId, surfaces);
|
|||
|
||||
tree_id!(SurfaceNodeId);
|
||||
impl Node for WlSurface {
|
||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
if let Some(xdg) = self.xdg.get() {
|
||||
xdg.focus_parent(seat);
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> NodeId {
|
||||
self.node_id.into()
|
||||
}
|
||||
|
|
@ -658,8 +665,9 @@ impl Node for WlSurface {
|
|||
|
||||
fn focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
||||
if let Some(xdg) = self.xdg.get() {
|
||||
xdg.focus_surface.insert(seat.id(), self);
|
||||
xdg.focus_surface.insert(seat.id(), self.clone());
|
||||
}
|
||||
seat.focus_surface(&self);
|
||||
}
|
||||
|
||||
fn unfocus(&self, seat: &WlSeatGlobal) {
|
||||
|
|
@ -705,6 +713,19 @@ impl Node for WlSurface {
|
|||
fn dnd_motion(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
|
||||
dnd.seat.dnd_surface_motion(self, dnd, x, y);
|
||||
}
|
||||
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_surface(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
let children = self.children.borrow_mut();
|
||||
if let Some(c) = children.deref() {
|
||||
for child in c.subsurfaces.values() {
|
||||
visitor.visit_surface(&child.surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ struct PendingXdgSurfaceData {
|
|||
}
|
||||
|
||||
pub trait XdgSurfaceExt: Debug {
|
||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
||||
fn get_split(&self) -> Option<ContainerSplit> {
|
||||
None
|
||||
}
|
||||
|
|
@ -203,6 +207,12 @@ impl XdgSurface {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
if let Some(ext) = self.ext.get() {
|
||||
ext.focus_parent(seat);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn focus_surface(&self, seat: &WlSeatGlobal) -> Rc<WlSurface> {
|
||||
self.focus_surface
|
||||
.get(&seat.id())
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::leaks::Tracker;
|
|||
use crate::object::Object;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::walker::NodeVisitor;
|
||||
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
||||
use crate::utils::buffd::MsgParser;
|
||||
use crate::utils::buffd::MsgParserError;
|
||||
|
|
@ -272,6 +273,14 @@ impl Node for XdgPopup {
|
|||
self.xdg.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_popup(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_surface(&self.xdg.surface);
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
self.xdg.absolute_desired_extents.get()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::leaks::Tracker;
|
|||
use crate::object::Object;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::walker::NodeVisitor;
|
||||
use crate::tree::{ContainerNode, ContainerSplit, FindTreeResult};
|
||||
use crate::tree::{FloatNode, FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode};
|
||||
use crate::utils::buffd::MsgParser;
|
||||
|
|
@ -81,6 +82,7 @@ pub struct XdgToplevel {
|
|||
min_height: Cell<Option<i32>>,
|
||||
max_width: Cell<Option<i32>>,
|
||||
max_height: Cell<Option<i32>>,
|
||||
title: RefCell<String>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +115,7 @@ impl XdgToplevel {
|
|||
min_height: Cell::new(None),
|
||||
max_width: Cell::new(None),
|
||||
max_height: Cell::new(None),
|
||||
title: RefCell::new("".to_string()),
|
||||
tracker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -210,7 +213,13 @@ impl XdgToplevel {
|
|||
}
|
||||
|
||||
fn set_title(&self, parser: MsgParser<'_, '_>) -> Result<(), SetTitleError> {
|
||||
let _req: SetTitle = self.xdg.surface.client.parse(self, parser)?;
|
||||
let req: SetTitle = self.xdg.surface.client.parse(self, parser)?;
|
||||
let mut title = self.title.borrow_mut();
|
||||
title.clear();
|
||||
title.push_str(req.title);
|
||||
if let Some(parent) = self.parent_node.get() {
|
||||
parent.child_title_changed(self, &title);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -302,6 +311,16 @@ impl XdgToplevel {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn notify_parent(&self) {
|
||||
let parent = match self.parent_node.get() {
|
||||
Some(p) => p,
|
||||
_ => return,
|
||||
};
|
||||
let extents = self.xdg.extents.get();
|
||||
parent.child_size_changed(self, extents.width(), extents.height());
|
||||
parent.child_title_changed(self, self.title.borrow_mut().deref());
|
||||
}
|
||||
|
||||
fn map_child(self: &Rc<Self>, parent: &XdgToplevel) {
|
||||
let workspace = match parent.xdg.workspace.get() {
|
||||
Some(w) => w,
|
||||
|
|
@ -311,8 +330,8 @@ impl XdgToplevel {
|
|||
let output = workspace.output.get();
|
||||
let output_rect = output.position.get();
|
||||
log::info!("or = {:?}", output_rect);
|
||||
let extents = self.xdg.extents.get();
|
||||
let position = {
|
||||
let extents = self.xdg.extents.get().to_origin();
|
||||
let width = extents.width();
|
||||
let height = extents.height();
|
||||
let mut x1 = output_rect.x1();
|
||||
|
|
@ -345,6 +364,7 @@ impl XdgToplevel {
|
|||
floater
|
||||
.workspace_link
|
||||
.set(Some(workspace.stacked.add_last(floater.clone())));
|
||||
self.notify_parent();
|
||||
}
|
||||
|
||||
fn map_tiled(self: &Rc<Self>) {
|
||||
|
|
@ -442,6 +462,14 @@ impl Node for XdgToplevel {
|
|||
self.xdg.seat_state.destroy_node(self)
|
||||
}
|
||||
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_toplevel(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_surface(&self.xdg.surface);
|
||||
}
|
||||
|
||||
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _direction: Direction) {
|
||||
seat.focus_toplevel(&self);
|
||||
}
|
||||
|
|
@ -488,6 +516,10 @@ impl Node for XdgToplevel {
|
|||
}
|
||||
|
||||
impl XdgSurfaceExt for XdgToplevel {
|
||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.parent_node.get().map(|p| p.focus_self(seat));
|
||||
}
|
||||
|
||||
fn get_split(&self) -> Option<ContainerSplit> {
|
||||
self.parent_node.get().and_then(|p| p.get_split())
|
||||
}
|
||||
|
|
@ -514,6 +546,7 @@ impl XdgSurfaceExt for XdgToplevel {
|
|||
));
|
||||
self.parent_node.set(Some(cn.clone()));
|
||||
pn.replace_child(&*self, cn);
|
||||
self.notify_parent();
|
||||
}
|
||||
|
||||
fn move_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
|
|
@ -574,9 +607,8 @@ impl XdgSurfaceExt for XdgToplevel {
|
|||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
if let Some(parent) = self.parent_node.get() {
|
||||
let extents = self.xdg.extents.get();
|
||||
parent.child_size_changed(self, extents.width(), extents.height());
|
||||
self.notify_parent();
|
||||
if self.parent_node.get().is_some() {
|
||||
self.xdg.surface.client.state.tree_changed();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
src/main.rs
11
src/main.rs
|
|
@ -8,7 +8,7 @@
|
|||
)]
|
||||
|
||||
use crate::acceptor::AcceptorError;
|
||||
use crate::async_engine::AsyncError;
|
||||
use crate::async_engine::{AsyncError, Phase};
|
||||
use crate::backends::dummy::DummyBackend;
|
||||
use crate::backends::xorg::{XorgBackend, XorgBackendError};
|
||||
use crate::client::Clients;
|
||||
|
|
@ -26,7 +26,7 @@ use crate::ifs::zxdg_decoration_manager_v1::ZxdgDecorationManagerV1Global;
|
|||
use crate::render::RenderError;
|
||||
use crate::sighand::SighandError;
|
||||
use crate::state::State;
|
||||
use crate::tree::{DisplayNode, NodeIds};
|
||||
use crate::tree::{container_layout, DisplayNode, NodeIds, render_titles};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::errorfmt::ErrorFmt;
|
||||
use crate::utils::numcell::NumCell;
|
||||
|
|
@ -71,6 +71,7 @@ mod servermem;
|
|||
mod sighand;
|
||||
mod state;
|
||||
mod tasks;
|
||||
mod text;
|
||||
mod theme;
|
||||
mod time;
|
||||
mod tree;
|
||||
|
|
@ -155,7 +156,8 @@ fn main_() -> Result<(), MainError> {
|
|||
mouse_ids: Default::default(),
|
||||
kb_handlers: Default::default(),
|
||||
theme: Default::default(),
|
||||
pending_layout: Default::default(),
|
||||
pending_container_layout: Default::default(),
|
||||
pending_container_titles: Default::default(),
|
||||
});
|
||||
forker.install(&state);
|
||||
let backend = XorgBackend::new(&state)?;
|
||||
|
|
@ -164,7 +166,8 @@ 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 _do_layout = engine.spawn2(Phase::Layout, container_layout(state.clone()));
|
||||
let _render_titles = engine.spawn2(Phase::PostLayout, render_titles(state.clone()));
|
||||
let socket_path = Acceptor::install(&state)?;
|
||||
forker.setenv(b"WAYLAND_DISPLAY", socket_path.as_bytes());
|
||||
el.run()?;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ impl Rect {
|
|||
self.x1 == self.x2 || self.y1 == self.y2
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn to_origin(&self) -> Self {
|
||||
Self {
|
||||
x1: 0,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::format::Format;
|
||||
use crate::format::{Format, ARGB8888};
|
||||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
|
|
@ -16,7 +16,7 @@ use crate::render::Texture;
|
|||
use crate::tree::{
|
||||
ContainerFocus, ContainerNode, ContainerSplit, FloatNode, OutputNode, WorkspaceNode,
|
||||
};
|
||||
use crate::State;
|
||||
use crate::{State};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::slice;
|
||||
|
|
@ -34,7 +34,7 @@ fn focus_color(focus: ContainerFocus) -> (f32, f32, f32) {
|
|||
}
|
||||
|
||||
pub struct Renderer<'a> {
|
||||
pub(super) ctx: &'a RenderContext,
|
||||
pub(super) ctx: &'a Rc<RenderContext>,
|
||||
pub(super) fb: &'a GlFrameBuffer,
|
||||
pub(super) state: &'a State,
|
||||
}
|
||||
|
|
@ -111,6 +111,7 @@ impl Renderer<'_> {
|
|||
let title_rect = Rect::new_sized(x, y, container.width.get(), title_height).unwrap();
|
||||
let underline_rect =
|
||||
Rect::new_sized(x, y + title_height, container.width.get(), 1).unwrap();
|
||||
let mut titles = vec![];
|
||||
if let Some(child) = container.mono_child.get() {
|
||||
let space_per_child = cwidth / num_children as i32;
|
||||
let mut rem = cwidth % num_children as i32;
|
||||
|
|
@ -127,6 +128,13 @@ impl Renderer<'_> {
|
|||
rem -= 1;
|
||||
width += 1;
|
||||
}
|
||||
if let Some(title) = child.title_texture.get() {
|
||||
titles.push((
|
||||
pos,
|
||||
0,
|
||||
title,
|
||||
));
|
||||
}
|
||||
if focus != ContainerFocus::None {
|
||||
let rect = Rect::new_sized(pos, y, width, title_height).unwrap();
|
||||
self.fill_boxes(slice::from_ref(&rect), r, g, b, 1.0);
|
||||
|
|
@ -154,6 +162,13 @@ impl Renderer<'_> {
|
|||
underline_rects.push(underline_rect);
|
||||
for (i, child) in container.children.iter().enumerate() {
|
||||
let body = child.body.get();
|
||||
if let Some(title) = child.title_texture.get() {
|
||||
titles.push((
|
||||
body.x1(),
|
||||
body.y1() - title_height - 1,
|
||||
title,
|
||||
));
|
||||
}
|
||||
if child.active.get() {
|
||||
active_rects.push(
|
||||
Rect::new_sized(
|
||||
|
|
@ -162,7 +177,7 @@ impl Renderer<'_> {
|
|||
body.width(),
|
||||
title_height,
|
||||
)
|
||||
.unwrap(),
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
if i + 1 < num_children {
|
||||
|
|
@ -208,6 +223,9 @@ impl Renderer<'_> {
|
|||
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 (tx, ty, tex) in titles {
|
||||
self.render_texture(&tex, x + tx, y + ty, ARGB8888);
|
||||
}
|
||||
}
|
||||
for child in container.children.iter() {
|
||||
let body = child.body.get();
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal};
|
|||
use crate::ifs::wl_surface::NoneSurfaceExt;
|
||||
use crate::render::RenderContext;
|
||||
use crate::theme::Theme;
|
||||
use crate::tree::{DisplayNode, Node, NodeIds};
|
||||
use crate::tree::{ContainerNode, DisplayNode, NodeIds};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::linkedlist::LinkedList;
|
||||
|
|
@ -56,7 +56,8 @@ pub struct State {
|
|||
pub tree_changed_sent: Cell<bool>,
|
||||
pub config: CloneCell<Option<Rc<ConfigProxy>>>,
|
||||
pub theme: Theme,
|
||||
pub pending_layout: AsyncQueue<Rc<dyn Node>>,
|
||||
pub pending_container_layout: AsyncQueue<Rc<ContainerNode>>,
|
||||
pub pending_container_titles: AsyncQueue<Rc<ContainerNode>>,
|
||||
}
|
||||
|
||||
pub struct MouseData {
|
||||
|
|
|
|||
|
|
@ -17,12 +17,3 @@ 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
67
src/text.rs
Normal file
67
src/text.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use crate::format::ARGB8888;
|
||||
use crate::render::{RenderContext, Texture};
|
||||
use crate::theme::Color;
|
||||
use crate::RenderError;
|
||||
use cairo::{ImageSurface, Operator};
|
||||
use pango::{EllipsizeMode, Layout};
|
||||
use pangocairo::cairo::Format;
|
||||
use pangocairo::pango::FontDescription;
|
||||
use pangocairo::{cairo, pango};
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TextError {
|
||||
#[error("Could not create a cairo image")]
|
||||
CreateImage(#[source] cairo::Error),
|
||||
#[error("Could not create a cairo context")]
|
||||
CairoContext(#[source] cairo::Error),
|
||||
#[error("Could not create a pango context")]
|
||||
PangoContext,
|
||||
#[error("Could not import the rendered text")]
|
||||
RenderError(#[source] RenderError),
|
||||
#[error("Could not access the cairo image data")]
|
||||
ImageData,
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
ctx: &Rc<RenderContext>,
|
||||
width: i32,
|
||||
height: i32,
|
||||
font: &str,
|
||||
text: &str,
|
||||
color: Color,
|
||||
) -> Result<Rc<Texture>, TextError> {
|
||||
let image = match ImageSurface::create(Format::ARgb32, width, height) {
|
||||
Ok(s) => s,
|
||||
Err(e) => return Err(TextError::CreateImage(e)),
|
||||
};
|
||||
let cctx = match cairo::Context::new(&image) {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(TextError::CairoContext(e)),
|
||||
};
|
||||
let pctx = match pangocairo::create_context(&cctx) {
|
||||
Some(c) => c,
|
||||
_ => return Err(TextError::PangoContext),
|
||||
};
|
||||
let fd = FontDescription::from_string(font);
|
||||
let layout = Layout::new(&pctx);
|
||||
layout.set_width(width * pango::SCALE);
|
||||
layout.set_ellipsize(EllipsizeMode::End);
|
||||
layout.set_font_description(Some(&fd));
|
||||
layout.set_text(text);
|
||||
cctx.set_operator(Operator::Source);
|
||||
cctx.set_source_rgba(color.r as _, color.g as _, color.b as _, color.a as _);
|
||||
pangocairo::show_layout(&cctx, &layout);
|
||||
let mut texture = None;
|
||||
let _ = image.with_data(|d| unsafe {
|
||||
let d = mem::transmute(d);
|
||||
texture = Some(ctx.shmem_texture(d, ARGB8888, width, height, image.stride()));
|
||||
});
|
||||
match texture {
|
||||
Some(Ok(t)) => Ok(t),
|
||||
Some(Err(e)) => Err(TextError::RenderError(e)),
|
||||
None => Err(TextError::ImageData),
|
||||
}
|
||||
}
|
||||
16
src/theme.rs
16
src/theme.rs
|
|
@ -1,5 +1,4 @@
|
|||
use crate::NumCell;
|
||||
use std::cell::Cell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Color {
|
||||
|
|
@ -9,6 +8,15 @@ pub struct Color {
|
|||
pub a: f32,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub const RED: Self = Self {
|
||||
r: 1.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
};
|
||||
}
|
||||
|
||||
fn to_f32(c: u8) -> f32 {
|
||||
c as f32 / 255 as f32
|
||||
}
|
||||
|
|
@ -43,7 +51,7 @@ pub struct Theme {
|
|||
pub border_color: Cell<Color>,
|
||||
pub title_height: Cell<i32>,
|
||||
pub border_width: Cell<i32>,
|
||||
pub version: NumCell<u32>,
|
||||
pub font: RefCell<String>,
|
||||
}
|
||||
|
||||
impl Default for Theme {
|
||||
|
|
@ -56,7 +64,7 @@ impl Default for Theme {
|
|||
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),
|
||||
font: RefCell::new("monospace 8".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
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::render::{Renderer, Texture};
|
||||
use crate::theme::Color;
|
||||
use crate::tree::walker::NodeVisitor;
|
||||
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef};
|
||||
use crate::{NumCell, State};
|
||||
use crate::{text, ErrorFmt, NumCell, State};
|
||||
use ahash::AHashMap;
|
||||
use i4config::{Axis, Direction};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::mem;
|
||||
use std::ops::DerefMut;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use crate::backend::KeyState;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -55,6 +57,7 @@ pub struct ContainerNode {
|
|||
pub id: ContainerNodeId,
|
||||
pub parent: CloneCell<Rc<dyn Node>>,
|
||||
pub split: Cell<ContainerSplit>,
|
||||
title: RefCell<String>,
|
||||
pub mono_child: CloneCell<Option<NodeRef<ContainerChild>>>,
|
||||
pub mono_body: Cell<Rect>,
|
||||
pub mono_content: Cell<Rect>,
|
||||
|
|
@ -65,8 +68,8 @@ pub struct ContainerNode {
|
|||
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>,
|
||||
layout_scheduled: Cell<bool>,
|
||||
render_titles_scheduled: Cell<bool>,
|
||||
num_children: NumCell<usize>,
|
||||
pub children: LinkedList<ContainerChild>,
|
||||
child_nodes: RefCell<AHashMap<NodeId, LinkedNode<ContainerChild>>>,
|
||||
|
|
@ -89,6 +92,8 @@ pub struct ContainerChild {
|
|||
pub content: Cell<Rect>,
|
||||
factor: Cell<f64>,
|
||||
pub focus: Cell<ContainerFocus>,
|
||||
title: RefCell<String>,
|
||||
pub title_texture: CloneCell<Option<Rc<Texture>>>,
|
||||
}
|
||||
|
||||
struct SeatState {
|
||||
|
|
@ -136,12 +141,15 @@ impl ContainerNode {
|
|||
content: Cell::new(Default::default()),
|
||||
factor: Cell::new(1.0),
|
||||
focus: Cell::new(ContainerFocus::None),
|
||||
title: Default::default(),
|
||||
title_texture: Default::default(),
|
||||
}),
|
||||
);
|
||||
Self {
|
||||
id: state.node_ids.next(),
|
||||
parent: CloneCell::new(parent),
|
||||
split: Cell::new(split),
|
||||
title: Default::default(),
|
||||
mono_child: CloneCell::new(None),
|
||||
mono_body: Cell::new(Default::default()),
|
||||
mono_content: Cell::new(Default::default()),
|
||||
|
|
@ -152,8 +160,8 @@ impl ContainerNode {
|
|||
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),
|
||||
layout_scheduled: Cell::new(false),
|
||||
render_titles_scheduled: Cell::new(false),
|
||||
num_children: NumCell::new(1),
|
||||
children,
|
||||
child_nodes: RefCell::new(child_nodes),
|
||||
|
|
@ -207,6 +215,8 @@ impl ContainerNode {
|
|||
content: Default::default(),
|
||||
factor: Cell::new(0.0),
|
||||
focus: Cell::new(ContainerFocus::None),
|
||||
title: Default::default(),
|
||||
title_texture: Default::default(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
@ -224,7 +234,8 @@ impl ContainerNode {
|
|||
child.factor.set(factor);
|
||||
sum_factors += factor;
|
||||
}
|
||||
self.apply_factors(sum_factors);
|
||||
self.sum_factors.set(sum_factors);
|
||||
self.schedule_layout();
|
||||
self.cancel_seat_ops();
|
||||
}
|
||||
|
||||
|
|
@ -235,16 +246,18 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
|
||||
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());
|
||||
pub fn on_theme_changed(self: &Rc<Self>) {
|
||||
self.update_content_size();
|
||||
self.schedule_layout();
|
||||
}
|
||||
|
||||
fn do_apply_factors(&self) {
|
||||
if self.theme_version.get() != self.state.theme.version.get() {
|
||||
self.update_content_size();
|
||||
fn schedule_layout(self: &Rc<Self>) {
|
||||
if !self.layout_scheduled.replace(true) {
|
||||
self.state.pending_container_layout.push(self.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn perform_layout(self: &Rc<Self>) {
|
||||
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();
|
||||
|
|
@ -305,12 +318,13 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
self.sum_factors.set(1.0);
|
||||
self.needs_layout.set(false);
|
||||
self.layout_scheduled.set(false);
|
||||
for child in self.children.iter() {
|
||||
let body = child.body.get().move_(self.abs_x1.get(), self.abs_y1.get());
|
||||
child.node.clone().change_extents(&body);
|
||||
child.position_content();
|
||||
}
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
|
||||
fn update_content_size(&self) {
|
||||
|
|
@ -335,7 +349,6 @@ impl ContainerNode {
|
|||
self.content_width.set(self.width.get());
|
||||
}
|
||||
}
|
||||
self.theme_version.set(self.state.theme.version.get());
|
||||
}
|
||||
|
||||
fn pointer_move(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>, mut x: i32, mut y: i32) {
|
||||
|
|
@ -390,7 +403,8 @@ impl ContainerNode {
|
|||
+ child_factor;
|
||||
prev.factor.set(prev_factor);
|
||||
op.child.factor.set(child_factor);
|
||||
self.apply_factors(sum_factors);
|
||||
self.sum_factors.set(sum_factors);
|
||||
self.schedule_layout();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -422,6 +436,59 @@ impl ContainerNode {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_title(self: &Rc<Self>) {
|
||||
let split = match self.split.get() {
|
||||
ContainerSplit::Horizontal => "H",
|
||||
ContainerSplit::Vertical => "V",
|
||||
};
|
||||
let mut title = self.title.borrow_mut();
|
||||
title.clear();
|
||||
title.push_str(split);
|
||||
title.push_str("[");
|
||||
for (i, c) in self.children.iter().enumerate() {
|
||||
if i > 0 {
|
||||
title.push_str(" ");
|
||||
}
|
||||
title.push_str(c.title.borrow_mut().deref());
|
||||
}
|
||||
title.push_str("]");
|
||||
self.parent.get().child_title_changed(&**self, &title);
|
||||
self.schedule_render_titles();
|
||||
}
|
||||
|
||||
fn schedule_render_titles(self: &Rc<Self>) {
|
||||
if !self.render_titles_scheduled.replace(true) {
|
||||
self.state.pending_container_titles.push(self.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn render_titles(&self) {
|
||||
let theme = &self.state.theme;
|
||||
let th = theme.title_height.get();
|
||||
let font = theme.font.borrow_mut();
|
||||
for c in self.children.iter() {
|
||||
c.title_texture.set(None);
|
||||
let title = c.title.borrow_mut();
|
||||
if title.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let ctx = match self.state.render_ctx.get() {
|
||||
Some(c) => c,
|
||||
_ => continue,
|
||||
};
|
||||
let texture =
|
||||
match text::render(&ctx, c.body.get().width(), th, &font, &title, Color::RED) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
log::error!("Could not render title {}: {}", title, ErrorFmt(e));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
c.title_texture.set(Some(texture));
|
||||
}
|
||||
self.render_titles_scheduled.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
struct SeatOp {
|
||||
|
|
@ -435,6 +502,24 @@ enum SeatOpKind {
|
|||
Resize { dist_left: i32, dist_right: i32 },
|
||||
}
|
||||
|
||||
pub async fn container_layout(state: Rc<State>) {
|
||||
loop {
|
||||
let container = state.pending_container_layout.pop().await;
|
||||
if container.layout_scheduled.get() {
|
||||
container.perform_layout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn render_titles(state: Rc<State>) {
|
||||
loop {
|
||||
let container = state.pending_container_titles.pop().await;
|
||||
if container.render_titles_scheduled.get() {
|
||||
container.render_titles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ContainerNode {
|
||||
fn id(&self) -> NodeId {
|
||||
self.id.into()
|
||||
|
|
@ -456,12 +541,32 @@ impl Node for ContainerNode {
|
|||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn needs_layout(&self) -> bool {
|
||||
self.needs_layout.get()
|
||||
fn child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) {
|
||||
let child = match self.child_nodes.borrow_mut().get(&child.id()) {
|
||||
Some(cn) => cn.to_ref(),
|
||||
_ => return,
|
||||
};
|
||||
{
|
||||
let mut ct = child.title.borrow_mut();
|
||||
if ct.deref() == title {
|
||||
return;
|
||||
}
|
||||
ct.clear();
|
||||
ct.push_str(title);
|
||||
}
|
||||
self.update_title();
|
||||
}
|
||||
|
||||
fn do_layout(&self) {
|
||||
self.do_apply_factors();
|
||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.parent.get().focus_self(seat);
|
||||
}
|
||||
|
||||
fn active_changed(&self, active: bool) {
|
||||
self.parent.get().child_active_changed(self, active);
|
||||
}
|
||||
|
||||
fn focus_self(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
||||
seat.focus_node(self);
|
||||
}
|
||||
|
||||
fn get_split(&self) -> Option<ContainerSplit> {
|
||||
|
|
@ -471,7 +576,7 @@ impl Node for ContainerNode {
|
|||
fn set_split(self: Rc<Self>, split: ContainerSplit) {
|
||||
self.split.set(split);
|
||||
self.update_content_size();
|
||||
self.apply_factors(self.sum_factors.get());
|
||||
self.schedule_layout();
|
||||
}
|
||||
|
||||
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
|
|
@ -647,6 +752,8 @@ impl Node for ContainerNode {
|
|||
content: Cell::new(node.content.get()),
|
||||
factor: Cell::new(node.factor.get()),
|
||||
focus: Cell::new(node.focus.get()),
|
||||
title: Default::default(),
|
||||
title_texture: Default::default(),
|
||||
});
|
||||
self.child_nodes.borrow_mut().insert(new.id(), link);
|
||||
new.clone().set_workspace(&self.workspace.get());
|
||||
|
|
@ -681,7 +788,8 @@ impl Node for ContainerNode {
|
|||
sum += factor;
|
||||
}
|
||||
}
|
||||
self.apply_factors(sum);
|
||||
self.sum_factors.set(sum);
|
||||
self.schedule_layout();
|
||||
self.cancel_seat_ops();
|
||||
}
|
||||
|
||||
|
|
@ -718,13 +826,9 @@ impl Node for ContainerNode {
|
|||
}
|
||||
|
||||
fn child_active_changed(&self, child: &dyn Node, active: bool) {
|
||||
log::info!("cac = {}", active);
|
||||
let node = match self.child_nodes.borrow_mut().get(&child.id()) {
|
||||
Some(l) => l.to_ref(),
|
||||
None => {
|
||||
log::info!("return");
|
||||
return
|
||||
},
|
||||
None => return,
|
||||
};
|
||||
node.active.set(active);
|
||||
}
|
||||
|
|
@ -745,7 +849,7 @@ impl Node for ContainerNode {
|
|||
size_changed |= self.height.replace(rect.height()) != rect.height();
|
||||
if size_changed {
|
||||
self.update_content_size();
|
||||
self.do_apply_factors();
|
||||
self.perform_layout();
|
||||
self.cancel_seat_ops();
|
||||
self.parent
|
||||
.get()
|
||||
|
|
@ -764,4 +868,14 @@ impl Node for ContainerNode {
|
|||
}
|
||||
self.workspace.set(ws.clone());
|
||||
}
|
||||
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_container(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
for child in self.children.iter() {
|
||||
child.node.clone().visit(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use crate::ifs::wl_seat::{Dnd, NodeSeatState, WlSeatGlobal};
|
|||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::walker::NodeVisitor;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::linkedlist::{LinkedList, LinkedNode};
|
||||
|
|
@ -21,6 +22,7 @@ use std::rc::Rc;
|
|||
pub use workspace::*;
|
||||
|
||||
mod container;
|
||||
pub mod walker;
|
||||
mod workspace;
|
||||
|
||||
pub struct NodeIds {
|
||||
|
|
@ -66,13 +68,12 @@ pub trait Node {
|
|||
fn id(&self) -> NodeId;
|
||||
fn seat_state(&self) -> &NodeSeatState;
|
||||
fn destroy_node(&self, detach: bool);
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor);
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor);
|
||||
|
||||
fn needs_layout(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn do_layout(&self) {
|
||||
// nothing
|
||||
fn child_title_changed(self: Rc<Self>, child: &dyn Node, title: &str) {
|
||||
let _ = child;
|
||||
let _ = title;
|
||||
}
|
||||
|
||||
fn get_parent_split(&self) -> Option<ContainerSplit> {
|
||||
|
|
@ -95,6 +96,10 @@ pub trait Node {
|
|||
let _ = split;
|
||||
}
|
||||
|
||||
fn focus_self(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
||||
fn do_focus(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, direction: Direction) {
|
||||
let _ = seat;
|
||||
let _ = direction;
|
||||
|
|
@ -155,6 +160,10 @@ pub trait Node {
|
|||
let _ = seat;
|
||||
}
|
||||
|
||||
fn focus_parent(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
||||
fn unfocus(&self, seat: &WlSeatGlobal) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
|
@ -279,7 +288,6 @@ 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 {
|
||||
|
|
@ -289,7 +297,6 @@ impl DisplayNode {
|
|||
outputs: Default::default(),
|
||||
stacked: Default::default(),
|
||||
seat_state: Default::default(),
|
||||
needs_layout: Cell::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -315,15 +322,17 @@ impl Node for DisplayNode {
|
|||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn needs_layout(&self) -> bool {
|
||||
self.needs_layout.get()
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_display(&self);
|
||||
}
|
||||
|
||||
fn do_layout(&self) {
|
||||
self.needs_layout.set(false);
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
let outputs = self.outputs.lock();
|
||||
for output in outputs.values() {
|
||||
output.do_layout();
|
||||
for (_, output) in outputs.deref() {
|
||||
visitor.visit_output(output);
|
||||
}
|
||||
for stacked in self.stacked.iter() {
|
||||
stacked.deref().clone().visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -409,10 +418,14 @@ 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 visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_output(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
let ws = self.workspaces.borrow_mut();
|
||||
for ws in ws.deref() {
|
||||
visitor.visit_workspace(ws);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -489,6 +502,16 @@ impl Node for FloatNode {
|
|||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_float(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
if let Some(c) = self.child.get() {
|
||||
c.visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
self.position.get()
|
||||
}
|
||||
|
|
|
|||
96
src/tree/walker.rs
Normal file
96
src/tree/walker.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::WlSurface;
|
||||
use crate::tree::{ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode};
|
||||
use crate::DisplayNode;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub trait NodeVisitorBase: Sized {
|
||||
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_popup(&mut self, node: &Rc<XdgPopup>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_display(&mut self, node: &Rc<DisplayNode>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_output(&mut self, node: &Rc<OutputNode>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
|
||||
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
|
||||
node.visit_children(self);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeVisitor {
|
||||
fn visit_surface(&mut self, node: &Rc<WlSurface>);
|
||||
fn visit_container(&mut self, node: &Rc<ContainerNode>);
|
||||
fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>);
|
||||
fn visit_popup(&mut self, node: &Rc<XdgPopup>);
|
||||
fn visit_display(&mut self, node: &Rc<DisplayNode>);
|
||||
fn visit_output(&mut self, node: &Rc<OutputNode>);
|
||||
fn visit_float(&mut self, node: &Rc<FloatNode>);
|
||||
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>);
|
||||
}
|
||||
|
||||
impl<T: NodeVisitorBase> NodeVisitor for T {
|
||||
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
||||
<T as NodeVisitorBase>::visit_surface(self, node)
|
||||
}
|
||||
|
||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||
<T as NodeVisitorBase>::visit_container(self, node)
|
||||
}
|
||||
|
||||
fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>) {
|
||||
<T as NodeVisitorBase>::visit_toplevel(self, node)
|
||||
}
|
||||
|
||||
fn visit_popup(&mut self, node: &Rc<XdgPopup>) {
|
||||
<T as NodeVisitorBase>::visit_popup(self, node)
|
||||
}
|
||||
|
||||
fn visit_display(&mut self, node: &Rc<DisplayNode>) {
|
||||
<T as NodeVisitorBase>::visit_display(self, node)
|
||||
}
|
||||
|
||||
fn visit_output(&mut self, node: &Rc<OutputNode>) {
|
||||
<T as NodeVisitorBase>::visit_output(self, node)
|
||||
}
|
||||
|
||||
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||
<T as NodeVisitorBase>::visit_float(self, node)
|
||||
}
|
||||
|
||||
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
|
||||
<T as NodeVisitorBase>::visit_workspace(self, node)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_containers<F: FnMut(&Rc<ContainerNode>)>(f: F) -> impl NodeVisitor {
|
||||
struct V<F>(F);
|
||||
impl<F: FnMut(&Rc<ContainerNode>)> NodeVisitorBase for V<F> {
|
||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||
(self.0)(node);
|
||||
node.visit_children(self);
|
||||
}
|
||||
}
|
||||
V(f)
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
|
|||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::container::ContainerNode;
|
||||
use crate::tree::walker::NodeVisitor;
|
||||
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, OutputNode};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::linkedlist::LinkedList;
|
||||
|
|
@ -47,12 +48,13 @@ impl Node for WorkspaceNode {
|
|||
self.seat_state.destroy_node(self);
|
||||
}
|
||||
|
||||
fn do_layout(&self) {
|
||||
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
|
||||
visitor.visit_workspace(&self);
|
||||
}
|
||||
|
||||
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
|
||||
if let Some(c) = self.container.get() {
|
||||
c.do_layout();
|
||||
}
|
||||
for s in self.stacked.iter() {
|
||||
s.do_layout();
|
||||
visitor.visit_container(&c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
11
src/utils/array.rs
Normal file
11
src/utils/array.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
pub fn from_fn<F, T, const N: usize>(mut cb: F) -> [T; N]
|
||||
where
|
||||
F: FnMut(usize) -> T,
|
||||
{
|
||||
let mut idx = 0;
|
||||
[(); N].map(|_| {
|
||||
let res = cb(idx);
|
||||
idx += 1;
|
||||
res
|
||||
})
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod array;
|
||||
pub mod asyncevent;
|
||||
pub mod bitflags;
|
||||
pub mod buffd;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::cell::RefCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::VecDeque;
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
|
|
@ -7,7 +7,7 @@ use std::task::{Context, Poll, Waker};
|
|||
|
||||
pub struct AsyncQueue<T> {
|
||||
data: RefCell<VecDeque<T>>,
|
||||
waiters: RefCell<Vec<Waker>>,
|
||||
waiter: Cell<Option<Waker>>,
|
||||
}
|
||||
|
||||
impl<T> Default for AsyncQueue<T> {
|
||||
|
|
@ -19,14 +19,14 @@ impl<T> Default for AsyncQueue<T> {
|
|||
impl<T> AsyncQueue<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: RefCell::new(Default::default()),
|
||||
waiters: RefCell::new(vec![]),
|
||||
data: Default::default(),
|
||||
waiter: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&self, t: T) {
|
||||
self.data.borrow_mut().push_back(t);
|
||||
for waiter in self.waiters.borrow_mut().drain(..) {
|
||||
if let Some(waiter) = self.waiter.take() {
|
||||
waiter.wake();
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ impl<T> AsyncQueue<T> {
|
|||
|
||||
pub fn clear(&self) {
|
||||
mem::take(&mut *self.data.borrow_mut());
|
||||
mem::take(&mut *self.waiters.borrow_mut());
|
||||
self.waiter.take();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ impl<'a, T> Future for AsyncQueuePop<'a, T> {
|
|||
if let Some(t) = self.queue.try_pop() {
|
||||
Poll::Ready(t)
|
||||
} else {
|
||||
self.queue.waiters.borrow_mut().push(cx.waker().clone());
|
||||
self.queue.waiter.set(Some(cx.waker().clone()));
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
todo.md
4
todo.md
|
|
@ -3,10 +3,8 @@
|
|||
- Container moving (mouse)
|
||||
- Container moving (kb)
|
||||
- Float toggle
|
||||
- Toplevel splitting
|
||||
- Workspaces
|
||||
- Float moving
|
||||
- Highlighting active
|
||||
- presentation time
|
||||
- viewporter
|
||||
- session lock
|
||||
|
|
@ -19,3 +17,5 @@
|
|||
- dnd
|
||||
- Shortcuts
|
||||
- Config
|
||||
- Highlighting active
|
||||
- Toplevel splitting
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue