1
0
Fork 0
forked from wry/wry

Merge pull request #847 from mahkoh/jorth/various-refactors

Various refactors
This commit is contained in:
mahkoh 2026-04-02 19:21:35 +02:00 committed by GitHub
commit b87eb60e68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 146 additions and 177 deletions

View file

@ -10,13 +10,13 @@ use {
wl_display::WlDisplay, wl_display::WlDisplay,
wl_registry::WlRegistry, wl_registry::WlRegistry,
wl_surface::{WlSurface, commit_timeline::CommitTimelines}, wl_surface::{WlSurface, commit_timeline::CommitTimelines},
xdg_activation_token_v1::ActivationToken,
}, },
leaks::Tracker, leaks::Tracker,
object::{Interface, Object, ObjectId, WL_DISPLAY_ID}, object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
security_context_acceptor::AcceptorMetadata, security_context_acceptor::AcceptorMetadata,
state::State, state::State,
utils::{ utils::{
activation_token::ActivationToken,
asyncevent::AsyncEvent, asyncevent::AsyncEvent,
buffd::{MsgFormatter, MsgParser, MsgParserError, OutBufferSwapchain}, buffd::{MsgFormatter, MsgParser, MsgParserError, OutBufferSwapchain},
copyhashmap::{CopyHashMap, Locked}, copyhashmap::{CopyHashMap, Locked},

View file

@ -9,13 +9,12 @@ use {
config::handler::ConfigProxyHandler, config::handler::ConfigProxyHandler,
ifs::wl_seat::SeatId, ifs::wl_seat::SeatId,
state::State, state::State,
tree::{TileState, ToplevelData}, tree::{TileState, ToplevelData, ToplevelIdentifier},
utils::{ utils::{
clonecell::CloneCell, clonecell::CloneCell,
nice::{JAY_NO_REALTIME, dont_allow_config_so}, nice::{JAY_NO_REALTIME, dont_allow_config_so},
numcell::NumCell, numcell::NumCell,
ptr_ext::PtrExt, ptr_ext::PtrExt,
toplevel_identifier::ToplevelIdentifier,
unlink_on_drop::UnlinkOnDrop, unlink_on_drop::UnlinkOnDrop,
xrd::xrd, xrd::xrd,
}, },

View file

@ -28,8 +28,8 @@ use {
tagged_acceptor::TaggedAcceptorError, tagged_acceptor::TaggedAcceptorError,
theme::{ThemeColor, ThemeSized}, theme::{ThemeColor, ThemeSized},
tree::{ tree::{
ContainerSplit, OutputNode, TearingMode, TileState, ToplevelData, ToplevelNode, ContainerSplit, OutputNode, TearingMode, TileState, ToplevelData, ToplevelIdentifier,
VrrMode, WorkspaceNode, toplevel_create_split, toplevel_parent_container, ToplevelNode, VrrMode, WorkspaceNode, toplevel_create_split, toplevel_parent_container,
toplevel_set_floating, toplevel_set_workspace, toplevel_set_floating, toplevel_set_workspace,
}, },
utils::{ utils::{
@ -40,7 +40,6 @@ use {
oserror::{OsError, OsErrorExt}, oserror::{OsError, OsErrorExt},
stack::Stack, stack::Stack,
timer::{TimerError, TimerFd}, timer::{TimerError, TimerFd},
toplevel_identifier::ToplevelIdentifier,
}, },
}, },
bincode::Options, bincode::Options,

View file

@ -10,11 +10,8 @@ use {
criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher}, criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher},
egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW, egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW,
state::State, state::State,
tree::ToplevelData, tree::{ToplevelData, ToplevelIdentifier},
utils::{ utils::{copyhashmap::CopyHashMap, static_text::StaticText},
copyhashmap::CopyHashMap, static_text::StaticText,
toplevel_identifier::ToplevelIdentifier,
},
}, },
ahash::AHashMap, ahash::AHashMap,
egui::{ egui::{

View file

@ -9,12 +9,11 @@ use {
criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher}, criteria::{CritMgrExt, CritUpstreamNode, crit_leaf::CritLeafMatcher},
egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW, egui_adapter::egui_platform::icons::ICON_OPEN_IN_NEW,
state::State, state::State,
tree::{NodeId, ToplevelData, ToplevelNode, ToplevelType}, tree::{NodeId, ToplevelData, ToplevelIdentifier, ToplevelNode, ToplevelType},
utils::{ utils::{
copyhashmap::CopyHashMap, copyhashmap::CopyHashMap,
event_listener::{EventListener, LazyEventSourceListener}, event_listener::{EventListener, LazyEventSourceListener},
static_text::StaticText, static_text::StaticText,
toplevel_identifier::ToplevelIdentifier,
}, },
}, },
ahash::AHashMap, ahash::AHashMap,

View file

@ -29,11 +29,8 @@ use {
}, },
ifs::wl_seat::WlSeatGlobal, ifs::wl_seat::WlSeatGlobal,
state::State, state::State,
tree::{NodeId, ToplevelData, ToplevelNode}, tree::{NodeId, ToplevelData, ToplevelIdentifier, ToplevelNode},
utils::{ utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, queue::AsyncQueue},
copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, queue::AsyncQueue,
toplevel_identifier::ToplevelIdentifier,
},
}, },
jay_config::window::{ContentType, WindowType}, jay_config::window::{ContentType, WindowType},
linearize::static_map, linearize::static_map,

View file

@ -18,53 +18,6 @@ macro_rules! egl_transparent {
}; };
} }
macro_rules! dynload {
(
$item:ident: $container:ident from $name:literal {
$(
$fun:ident: $ty:ty,
)*
}
) => {
#[expect(non_snake_case)]
#[derive(Debug)]
pub struct $container {
_lib: libloading::Library,
$(
pub $fun: $ty,
)*
}
pub static $item: std::sync::LazyLock<Option<$container>> = std::sync::LazyLock::new(|| unsafe {
use crate::utils::errorfmt::ErrorFmt;
let lib = match libloading::Library::new($name) {
Ok(l) => l,
Err(e) => {
log::error!("Could not load lib{}: {}", $name, ErrorFmt(e));
return None;
}
};
$(
#[expect(non_snake_case)]
let $fun: $ty =
match lib.get(stringify!($fun).as_bytes()) {
Ok(s) => *s,
Err(e) => {
log::error!("Could not load {} from {}: {}", stringify!($fun), $name, ErrorFmt(e));
return None;
}
};
)*
Some($container {
_lib: lib,
$(
$fun,
)*
})
});
};
}
use { use {
crate::{ crate::{
cmm::cmm_eotf::Eotf, cmm::cmm_eotf::Eotf,

View file

@ -30,7 +30,8 @@ use {
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
screenshoter::take_screenshot, screenshoter::take_screenshot,
utils::{errorfmt::ErrorFmt, toplevel_identifier::ToplevelIdentifier}, tree::ToplevelIdentifier,
utils::errorfmt::ErrorFmt,
wire::{ wire::{
JayCompositorId, JayScreenshotId, JayCompositorId, JayScreenshotId,
jay_compositor::{self, *}, jay_compositor::{self, *},

View file

@ -16,9 +16,10 @@ use {
rect::Rect, rect::Rect,
tree::{ tree::{
self, ContainerNode, DisplayNode, FloatNode, Node, NodeVisitor, OutputNode, self, ContainerNode, DisplayNode, FloatNode, Node, NodeVisitor, OutputNode,
PlaceholderNode, ToplevelData, ToplevelNodeBase, ToplevelType, WorkspaceNode, PlaceholderNode, ToplevelData, ToplevelIdentifier, ToplevelNodeBase, ToplevelType,
WorkspaceNode,
}, },
utils::{opaque::OpaqueError, opt::Opt, toplevel_identifier::ToplevelIdentifier}, utils::{opaque::OpaqueError, opt::Opt},
wire::{JayTreeQueryId, jay_tree_query::*}, wire::{JayTreeQueryId, jay_tree_query::*},
}, },
isnt::std_1::primitive::IsntStrExt, isnt::std_1::primitive::IsntStrExt,

View file

@ -3,13 +3,14 @@ use {
client::{Client, ClientError}, client::{Client, ClientError},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
utils::activation_token::{ActivationToken, activation_token},
wire::{XdgActivationTokenV1Id, xdg_activation_token_v1::*}, wire::{XdgActivationTokenV1Id, xdg_activation_token_v1::*},
}, },
std::{cell::Cell, rc::Rc}, std::{cell::Cell, rc::Rc},
thiserror::Error, thiserror::Error,
}; };
opaque!(ActivationToken, activation_token);
const MAX_TOKENS_PER_CLIENT: usize = 8; const MAX_TOKENS_PER_CLIENT: usize = 8;
pub struct XdgActivationTokenV1 { pub struct XdgActivationTokenV1 {

View file

@ -2,10 +2,10 @@ use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
globals::{Global, GlobalName}, globals::{Global, GlobalName},
ifs::xdg_activation_token_v1::XdgActivationTokenV1, ifs::xdg_activation_token_v1::{ActivationToken, XdgActivationTokenV1},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
utils::{activation_token::ActivationToken, errorfmt::ErrorFmt, opaque::OpaqueError}, utils::{errorfmt::ErrorFmt, opaque::OpaqueError},
wire::{XdgActivationV1Id, xdg_activation_v1::*}, wire::{XdgActivationV1Id, xdg_activation_v1::*},
}, },
std::rc::Rc, std::rc::Rc,

View file

@ -853,3 +853,83 @@ macro_rules! dbg {
} }
}; };
} }
macro_rules! dynload {
(
$item:ident: $container:ident from $name:literal {
$(
$fun:ident: $ty:ty,
)*
}
) => {
#[expect(non_snake_case)]
#[derive(Debug)]
pub struct $container {
_lib: libloading::Library,
$(
pub $fun: $ty,
)*
}
pub static $item: std::sync::LazyLock<Option<$container>> = std::sync::LazyLock::new(|| unsafe {
use crate::utils::errorfmt::ErrorFmt;
let lib = match libloading::Library::new($name) {
Ok(l) => l,
Err(e) => {
log::error!("Could not load {}: {}", $name, ErrorFmt(e));
return None;
}
};
$(
#[allow(clippy::allow_attributes, non_snake_case)]
let $fun: $ty =
match lib.get(stringify!($fun).as_bytes()) {
Ok(s) => *s,
Err(e) => {
log::error!("Could not load {} from {}: {}", stringify!($fun), $name, ErrorFmt(e));
return None;
}
};
)*
Some($container {
_lib: lib,
$(
$fun,
)*
})
});
};
}
macro_rules! opaque {
($ty:ident, $fun:ident) => {
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, Ord, PartialOrd)]
pub struct $ty(crate::utils::opaque::Opaque);
unsafe impl crate::utils::clonecell::UnsafeCellCloneSafe for $ty {}
pub fn $fun() -> $ty {
$ty(crate::utils::opaque::opaque())
}
impl $ty {
pub fn to_string(self) -> arrayvec::ArrayString<{ crate::utils::opaque::OPAQUE_LEN }> {
self.0.to_string()
}
}
impl std::fmt::Display for $ty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::str::FromStr for $ty {
type Err = crate::utils::opaque::OpaqueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.parse()?))
}
}
};
}

View file

@ -87,6 +87,7 @@ use {
workspace_manager::WorkspaceManagerState, workspace_manager::WorkspaceManagerState,
wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1, wp_drm_lease_connector_v1::WpDrmLeaseConnectorV1,
wp_drm_lease_device_v1::WpDrmLeaseDeviceV1Global, wp_drm_lease_device_v1::WpDrmLeaseDeviceV1Global,
xdg_activation_token_v1::ActivationToken,
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1, zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1,
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1, zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1,
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1, zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
@ -107,13 +108,12 @@ use {
tree::{ tree::{
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode, ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
FoundNode, LatchListener, Node, NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode, FoundNode, LatchListener, Node, NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode,
TearingMode, TileState, ToplevelData, ToplevelNode, ToplevelNodeBase, Transform, TearingMode, TileState, ToplevelData, ToplevelIdentifier, ToplevelNode,
VrrMode, WorkspaceDisplayOrder, WorkspaceNode, WsMoveConfig, generic_node_visitor, ToplevelNodeBase, Transform, VrrMode, WorkspaceDisplayOrder, WorkspaceNode,
move_ws_to_output, WsMoveConfig, generic_node_visitor, move_ws_to_output,
}, },
udmabuf::UdmabufHolder, udmabuf::UdmabufHolder,
utils::{ utils::{
activation_token::ActivationToken,
asyncevent::AsyncEvent, asyncevent::AsyncEvent,
bindings::Bindings, bindings::Bindings,
clonecell::CloneCell, clonecell::CloneCell,
@ -128,7 +128,6 @@ use {
queue::AsyncQueue, queue::AsyncQueue,
refcounted::RefCounted, refcounted::RefCounted,
run_toplevel::RunToplevel, run_toplevel::RunToplevel,
toplevel_identifier::ToplevelIdentifier,
}, },
video::{ video::{
dmabuf::DmaBufIds, dmabuf::DmaBufIds,

View file

@ -31,15 +31,9 @@ use {
NodeLayerLink, OutputNode, PlaceholderNode, WorkspaceNode, NodeLayerLink, OutputNode, PlaceholderNode, WorkspaceNode,
}, },
utils::{ utils::{
array_to_tuple::ArrayToTuple, array_to_tuple::ArrayToTuple, clonecell::CloneCell, copyhashmap::CopyHashMap,
clonecell::CloneCell, event_listener::LazyEventSource, hash_map_ext::HashMapExt, numcell::NumCell,
copyhashmap::CopyHashMap, rc_eq::rc_eq, threshold_counter::ThresholdCounter,
event_listener::LazyEventSource,
hash_map_ext::HashMapExt,
numcell::NumCell,
rc_eq::rc_eq,
threshold_counter::ThresholdCounter,
toplevel_identifier::{ToplevelIdentifier, toplevel_identifier},
}, },
wire::{ wire::{
ExtForeignToplevelHandleV1Id, ExtImageCopyCaptureSessionV1Id, JayScreencastId, ExtForeignToplevelHandleV1Id, ExtImageCopyCaptureSessionV1Id, JayScreencastId,
@ -55,6 +49,8 @@ use {
}, },
}; };
opaque!(ToplevelIdentifier, toplevel_identifier);
tree_id!(ToplevelNodeId); tree_id!(ToplevelNodeId);
pub trait ToplevelNode: ToplevelNodeBase { pub trait ToplevelNode: ToplevelNodeBase {

View file

@ -1,4 +1,3 @@
pub mod activation_token;
pub mod array; pub mod array;
pub mod array_to_tuple; pub mod array_to_tuple;
pub mod asyncevent; pub mod asyncevent;
@ -60,7 +59,6 @@ pub mod string_ext;
pub mod syncqueue; pub mod syncqueue;
pub mod threshold_counter; pub mod threshold_counter;
pub mod timer; pub mod timer;
pub mod toplevel_identifier;
pub mod tri; pub mod tri;
pub mod unlink_on_drop; pub mod unlink_on_drop;
pub mod vec_ext; pub mod vec_ext;

View file

@ -1,35 +0,0 @@
use {
crate::utils::opaque::{OPAQUE_LEN, Opaque, OpaqueError, opaque},
arrayvec::ArrayString,
std::{
fmt::{Display, Formatter},
str::FromStr,
},
};
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub struct ActivationToken(Opaque);
pub fn activation_token() -> ActivationToken {
ActivationToken(opaque())
}
impl ActivationToken {
pub fn to_string(self) -> ArrayString<OPAQUE_LEN> {
self.0.to_string()
}
}
impl Display for ActivationToken {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl FromStr for ActivationToken {
type Err = OpaqueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.parse()?))
}
}

View file

@ -1,4 +1,5 @@
use { use {
crate::utils::array,
arrayvec::ArrayString, arrayvec::ArrayString,
rand::{RngExt, rng}, rand::{RngExt, rng},
serde::{Deserialize, Deserializer, Serialize, Serializer, de}, serde::{Deserialize, Deserializer, Serialize, Serializer, de},
@ -10,17 +11,19 @@ use {
thiserror::Error, thiserror::Error,
}; };
#[cfg(test)]
mod tests;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(transparent)]
pub struct Opaque { pub struct Opaque {
lo: u64, v: [u64; 3],
hi: u64,
} }
pub fn opaque() -> Opaque { pub fn opaque() -> Opaque {
let mut rng = rng(); let mut rng = rng();
Opaque { Opaque {
lo: rng.random(), v: array::from_fn(|_| rng.random()),
hi: rng.random(),
} }
} }
@ -35,8 +38,9 @@ impl Opaque {
impl Display for Opaque { impl Display for Opaque {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:016x}", self.hi)?; write!(f, "{:016x}", self.v[2])?;
write!(f, "{:016x}", self.lo)?; write!(f, "{:016x}", self.v[1])?;
write!(f, "{:016x}", self.v[0])?;
Ok(()) Ok(())
} }
} }
@ -72,24 +76,32 @@ impl FromStr for Opaque {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() != OPAQUE_LEN { if s.len() != OPAQUE_LEN {
return Err(OpaqueError::InvalidLength); return Err(OpaqueError::InvalidStringLength);
} }
if !s.is_char_boundary(OPAQUE_LEN / 2) { if !s.is_char_boundary(OPAQUE_SEGMENT) {
return Err(OpaqueError::NotAscii); return Err(OpaqueError::NotAscii);
} }
let (hi, lo) = s.split_at(OPAQUE_LEN / 2); let (a, s) = s.split_at(OPAQUE_SEGMENT);
let hi = u64::from_str_radix(hi, 16).map_err(OpaqueError::Parse)?; if !s.is_char_boundary(OPAQUE_SEGMENT) {
let lo = u64::from_str_radix(lo, 16).map_err(OpaqueError::Parse)?; return Err(OpaqueError::NotAscii);
Ok(Self { lo, hi }) }
let (b, c) = s.split_at(OPAQUE_SEGMENT);
let v = [
u64::from_str_radix(c, 16).map_err(OpaqueError::Parse)?,
u64::from_str_radix(b, 16).map_err(OpaqueError::Parse)?,
u64::from_str_radix(a, 16).map_err(OpaqueError::Parse)?,
];
Ok(Self { v })
} }
} }
pub const OPAQUE_LEN: usize = 32; pub const OPAQUE_LEN: usize = 48;
const OPAQUE_SEGMENT: usize = OPAQUE_LEN / 3;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum OpaqueError { pub enum OpaqueError {
#[error("The string is not exactly 32 bytes long")] #[error("The string is not exactly {OPAQUE_LEN} bytes long")]
InvalidLength, InvalidStringLength,
#[error("The string is not ascii")] #[error("The string is not ascii")]
NotAscii, NotAscii,
#[error("Could not parse the string as a hex number")] #[error("Could not parse the string as a hex number")]

12
src/utils/opaque/tests.rs Normal file
View file

@ -0,0 +1,12 @@
use {
crate::utils::opaque::{Opaque, opaque},
std::str::FromStr,
};
#[test]
fn roundtrip() {
let v1 = opaque();
let s = v1.to_string();
let v2 = Opaque::from_str(&s).unwrap();
assert_eq!(v1, v2);
}

View file

@ -1,40 +0,0 @@
use {
crate::utils::{
clonecell::UnsafeCellCloneSafe,
opaque::{OPAQUE_LEN, Opaque, OpaqueError, opaque},
},
arrayvec::ArrayString,
std::{
fmt::{Display, Formatter},
str::FromStr,
},
};
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, Ord, PartialOrd)]
pub struct ToplevelIdentifier(Opaque);
unsafe impl UnsafeCellCloneSafe for ToplevelIdentifier {}
pub fn toplevel_identifier() -> ToplevelIdentifier {
ToplevelIdentifier(opaque())
}
impl ToplevelIdentifier {
pub fn to_string(self) -> ArrayString<OPAQUE_LEN> {
self.0.to_string()
}
}
impl Display for ToplevelIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl FromStr for ToplevelIdentifier {
type Err = OpaqueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.parse()?))
}
}