server: refactor to use ECS

This should simplify how some of the code reads, as well as allowing for future
feature additions to be accomplished in a less restrictive manner. The slotmap +
Object enum pattern was kind of like a really bad ecs in a way anyway. Also I
was looking for an excuse to use an ecs.
This commit is contained in:
Shawn Wallace 2025-06-13 20:43:21 -04:00
parent da2ecb5be8
commit 799027d1ae
11 changed files with 2046 additions and 1970 deletions

83
Cargo.lock generated
View file

@ -2,6 +2,18 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "ahash"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.3" version = "1.1.3"
@ -294,6 +306,37 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash",
]
[[package]]
name = "hecs"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cbc675ee8d97b4d206a985137f8ad59666538f56f906474f554467a63c776d"
dependencies = [
"hashbrown",
"hecs-macros",
"spin",
]
[[package]]
name = "hecs-macros"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052fc25b12dc326082605cd2098eb76050a72fa0c0e9ea7faaa3f58b565fc970"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.5.1" version = "0.5.1"
@ -421,6 +464,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
name = "macros" name = "macros"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"proc-macro2",
"quote", "quote",
"syn", "syn",
] ]
@ -655,15 +699,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "slotmap"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.15.0" version = "1.15.0"
@ -693,6 +728,12 @@ dependencies = [
"xkeysym", "xkeysym",
] ]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -1161,21 +1202,39 @@ dependencies = [
"anyhow", "anyhow",
"bitflags 2.9.1", "bitflags 2.9.1",
"env_logger 0.11.8", "env_logger 0.11.8",
"libc", "hecs",
"log", "log",
"macros", "macros",
"pretty_env_logger", "pretty_env_logger",
"rustix", "rustix",
"sd-notify", "sd-notify",
"slotmap",
"smithay-client-toolkit", "smithay-client-toolkit",
"testwl", "testwl",
"vergen-gitcl", "vergen-gitcl",
"wayland-client", "wayland-client",
"wayland-protocols", "wayland-protocols",
"wayland-scanner",
"wayland-server", "wayland-server",
"wl_drm", "wl_drm",
"xcb", "xcb",
"xcb-util-cursor", "xcb-util-cursor",
] ]
[[package]]
name = "zerocopy"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -26,20 +26,18 @@ bitflags = "2.5.0"
rustix = { workspace = true, features = ["event"] } rustix = { workspace = true, features = ["event"] }
wayland-client.workspace = true wayland-client.workspace = true
wayland-protocols = { workspace = true, features = ["client", "server", "staging", "unstable"] } wayland-protocols = { workspace = true, features = ["client", "server", "staging", "unstable"] }
wayland-scanner.workspace = true
wayland-server.workspace = true wayland-server.workspace = true
xcb = { version = "1.3.0", features = ["composite", "randr", "res"] } xcb = { version = "1.3.0", features = ["composite", "randr", "res"] }
wl_drm = { path = "wl_drm" } wl_drm = { path = "wl_drm" }
libc = "0.2.153"
log = "0.4.21" log = "0.4.21"
env_logger = "0.11.3" env_logger = "0.11.3"
pretty_env_logger = "0.5.0" pretty_env_logger = "0.5.0"
slotmap = "1.0.7"
xcb-util-cursor = "0.3.2" xcb-util-cursor = "0.3.2"
smithay-client-toolkit = { version = "0.19.1", default-features = false } smithay-client-toolkit = { version = "0.19.1", default-features = false }
sd-notify = { version = "0.4.2", optional = true } sd-notify = { version = "0.4.2", optional = true }
macros = { version = "0.1.0", path = "macros" } macros = { version = "0.1.0", path = "macros" }
hecs = { version = "0.10.5", features = ["macros"] }
[features] [features]
default = [] default = []

View file

@ -10,5 +10,6 @@ workspace = true
proc-macro = true proc-macro = true
[dependencies] [dependencies]
proc-macro2 = "1.0.95"
quote = "1.0.37" quote = "1.0.37"
syn = "2.0.79" syn = "2.0.79"

View file

@ -46,9 +46,32 @@ impl Parse for EventVariant {
} }
} }
enum ShuntObject {
Ident(syn::Ident),
KSelf(Token![self]),
}
impl Parse for ShuntObject {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if input.peek(Token![self]) {
Ok(Self::KSelf(input.parse()?))
} else {
Ok(Self::Ident(input.parse()?))
}
}
}
impl quote::ToTokens for ShuntObject {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
Self::Ident(i) => i.to_tokens(tokens),
Self::KSelf(s) => s.to_tokens(tokens),
}
}
}
struct Input { struct Input {
object: syn::Expr, object: syn::Expr,
event_object: syn::Ident, event_object: ShuntObject,
event_type: syn::Type, event_type: syn::Type,
events: Punctuated<EventVariant, Token![,]>, events: Punctuated<EventVariant, Token![,]>,
} }
@ -58,8 +81,12 @@ impl Parse for Input {
let object = input.parse()?; let object = input.parse()?;
input.parse::<Token![,]>()?; input.parse::<Token![,]>()?;
let event_object = input.parse()?; let event_object = input.parse()?;
let event_type = if matches!(event_object, ShuntObject::Ident(..)) {
input.parse::<Token![:]>()?; input.parse::<Token![:]>()?;
let event_type = input.parse()?; input.parse()?
} else {
parse_quote!(Self)
};
input.parse::<Token![=>]>()?; input.parse::<Token![=>]>()?;
let events; let events;
bracketed!(events in input); bracketed!(events in input);
@ -119,14 +146,13 @@ pub fn simple_event_shunt(tokens: TokenStream) -> TokenStream {
let fn_name = format_ident!("{keyword_pfx}{fn_name}"); let fn_name = format_ident!("{keyword_pfx}{fn_name}");
quote! { quote! {
#name { #field_names } => { #object.#fn_name(#fn_args); } #event_type::#name { #field_names } => { #object.#fn_name(#fn_args); }
} }
}); });
quote! {{ quote! {{
use #event_type::*;
match #event_object { match #event_object {
#(#match_arms)* #(#match_arms)*
_ => log::warn!(concat!("unhandled ", stringify!(#event_type), ": {:?}"), #event_object) _ => log::warn!("unhandled {}: {:?}", std::any::type_name::<#event_type>(), #event_object)
} }
}} }}
.into() .into()

View file

@ -1,133 +0,0 @@
use crate::clientside::Globals;
use smithay_client_toolkit::{
data_device_manager::{
data_device::DataDeviceHandler, data_offer::DataOfferHandler,
data_source::DataSourceHandler,
},
delegate_data_device,
};
delegate_data_device!(Globals);
impl DataDeviceHandler for Globals {
fn selection(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
data_device: &wayland_client::protocol::wl_data_device::WlDataDevice,
) {
self.selection = Some(data_device.clone());
}
fn drop_performed(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
) {
}
fn motion(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
_: f64,
_: f64,
) {
}
fn leave(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
) {
}
fn enter(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
_: f64,
_: f64,
_: &wayland_client::protocol::wl_surface::WlSurface,
) {
}
}
impl DataSourceHandler for Globals {
fn send_request(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
mime: String,
fd: smithay_client_toolkit::data_device_manager::WritePipe,
) {
self.selection_requests.push((mime, fd));
}
fn cancelled(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
self.cancelled = true;
}
fn action(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
_: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
}
fn dnd_finished(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
}
fn dnd_dropped(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
}
fn accept_mime(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
_: Option<String>,
) {
}
}
impl DataOfferHandler for Globals {
fn selected_action(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &mut smithay_client_toolkit::data_device_manager::data_offer::DragOffer,
_: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
}
fn source_actions(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &mut smithay_client_toolkit::data_device_manager::data_offer::DragOffer,
_: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
}
}

View file

@ -1,42 +0,0 @@
use smithay_client_toolkit::{
activation::{ActivationHandler, RequestData, RequestDataExt},
delegate_activation,
};
use xcb::x;
use crate::clientside::Globals;
delegate_activation!(Globals, ActivationData);
pub struct ActivationData {
window: x::Window,
data: RequestData,
}
impl ActivationData {
pub fn new(window: x::Window, data: RequestData) -> Self {
Self { window, data }
}
}
impl RequestDataExt for ActivationData {
fn app_id(&self) -> Option<&str> {
self.data.app_id()
}
fn seat_and_serial(&self) -> Option<(&wayland_client::protocol::wl_seat::WlSeat, u32)> {
self.data.seat_and_serial()
}
fn surface(&self) -> Option<&wayland_client::protocol::wl_surface::WlSurface> {
self.data.surface()
}
}
impl ActivationHandler for Globals {
type RequestData = ActivationData;
fn new_token(&mut self, token: String, data: &Self::RequestData) {
self.pending_activations.push((data.window, token));
}
}

View file

@ -1,4 +1,3 @@
mod clientside;
mod server; mod server;
pub mod xstate; pub mod xstate;

View file

@ -1,8 +1,13 @@
mod data_device; use super::ObjectEvent;
pub mod xdg_activation; use hecs::{Entity, World};
use smithay_client_toolkit::{
use crate::server::{ObjectEvent, ObjectKey}; activation::{ActivationHandler, RequestData, RequestDataExt},
use std::os::unix::net::UnixStream; data_device_manager::{
data_device::DataDeviceHandler, data_offer::DataOfferHandler,
data_source::DataSourceHandler,
},
delegate_activation, delegate_data_device,
};
use std::sync::{mpsc, Mutex, OnceLock}; use std::sync::{mpsc, Mutex, OnceLock};
use wayland_client::protocol::{ use wayland_client::protocol::{
wl_buffer::WlBuffer, wl_callback::WlCallback, wl_compositor::WlCompositor, wl_buffer::WlBuffer, wl_callback::WlCallback, wl_compositor::WlCompositor,
@ -12,16 +17,14 @@ use wayland_client::protocol::{
}; };
use wayland_client::{ use wayland_client::{
delegate_noop, event_created_child, delegate_noop, event_created_child,
globals::{registry_queue_init, Global, GlobalList, GlobalListContents}, globals::{Global, GlobalList, GlobalListContents},
Connection, Dispatch, EventQueue, Proxy, QueueHandle, Connection, Dispatch, Proxy, QueueHandle,
}; };
use wayland_protocols::wp::relative_pointer::zv1::client::{ use wayland_protocols::{
wp::relative_pointer::zv1::client::{
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
zwp_relative_pointer_v1::ZwpRelativePointerV1, zwp_relative_pointer_v1::ZwpRelativePointerV1,
}; },
use wayland_protocols::xdg::decoration::zv1::client::zxdg_decoration_manager_v1::ZxdgDecorationManagerV1;
use wayland_protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1;
use wayland_protocols::{
wp::{ wp::{
fractional_scale::v1::client::{ fractional_scale::v1::client::{
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1, wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
@ -52,6 +55,8 @@ use wayland_protocols::{
}, },
viewporter::client::{wp_viewport::WpViewport, wp_viewporter::WpViewporter}, viewporter::client::{wp_viewport::WpViewport, wp_viewporter::WpViewporter},
}, },
xdg::decoration::zv1::client::zxdg_decoration_manager_v1::ZxdgDecorationManagerV1,
xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
xdg::{ xdg::{
activation::v1::client::xdg_activation_v1::XdgActivationV1, activation::v1::client::xdg_activation_v1::XdgActivationV1,
shell::client::{ shell::client::{
@ -65,55 +70,56 @@ use wayland_protocols::{
}; };
use wayland_server::protocol as server; use wayland_server::protocol as server;
use wl_drm::client::wl_drm::WlDrm; use wl_drm::client::wl_drm::WlDrm;
use xcb::x;
#[derive(Default)] pub(super) struct MyWorld {
pub struct Globals { pub world: World,
events: Vec<(ObjectKey, ObjectEvent)>, pub global_list: GlobalList,
queued_events: Vec<mpsc::Receiver<(ObjectKey, ObjectEvent)>>,
pub new_globals: Vec<Global>, pub new_globals: Vec<Global>,
events: Vec<(Entity, ObjectEvent)>,
queued_events: Vec<mpsc::Receiver<(Entity, ObjectEvent)>>,
pub selection: Option<wayland_client::protocol::wl_data_device::WlDataDevice>, pub selection: Option<wayland_client::protocol::wl_data_device::WlDataDevice>,
pub selection_requests: Vec<( pub selection_requests: Vec<(
String, String,
smithay_client_toolkit::data_device_manager::WritePipe, smithay_client_toolkit::data_device_manager::WritePipe,
)>, )>,
pub cancelled: bool, pub selection_cancelled: bool,
pub pending_activations: Vec<(xcb::x::Window, String)>, pub pending_activations: Vec<(xcb::x::Window, String)>,
} }
pub type ClientQueueHandle = QueueHandle<Globals>; impl MyWorld {
pub fn new(global_list: GlobalList) -> Self {
pub struct ClientState { Self {
_connection: Connection, world: World::new(),
pub queue: EventQueue<Globals>, global_list,
pub qh: ClientQueueHandle, new_globals: Vec::new(),
pub globals: Globals, events: Vec::new(),
pub global_list: GlobalList, queued_events: Vec::new(),
selection: None,
selection_requests: Vec::new(),
selection_cancelled: false,
pending_activations: Vec::new(),
}
}
} }
impl ClientState { impl std::ops::Deref for MyWorld {
pub fn new(server_connection: Option<UnixStream>) -> Self { type Target = World;
let connection = if let Some(stream) = server_connection { fn deref(&self) -> &Self::Target {
Connection::from_socket(stream) &self.world
} else {
Connection::connect_to_env()
} }
.unwrap(); }
let (global_list, queue) = registry_queue_init::<Globals>(&connection).unwrap();
let globals = Globals::default();
let qh = queue.handle();
Self { impl std::ops::DerefMut for MyWorld {
_connection: connection, fn deref_mut(&mut self) -> &mut Self::Target {
queue, &mut self.world
qh,
globals,
global_list,
}
} }
}
pub fn read_events(&mut self) -> Vec<(ObjectKey, ObjectEvent)> { impl MyWorld {
let mut events = std::mem::take(&mut self.globals.events); pub(crate) fn read_events(&mut self) -> Vec<(Entity, ObjectEvent)> {
self.globals.queued_events.retain(|rx| { let mut events = std::mem::take(&mut self.events);
self.queued_events.retain(|rx| {
match rx.try_recv() { match rx.try_recv() {
Ok(event) => { Ok(event) => {
events.push(event); events.push(event);
@ -132,25 +138,25 @@ impl ClientState {
pub type Event<T> = <T as Proxy>::Event; pub type Event<T> = <T as Proxy>::Event;
delegate_noop!(Globals: WlCompositor); delegate_noop!(MyWorld: WlCompositor);
delegate_noop!(Globals: WlRegion); delegate_noop!(MyWorld: WlRegion);
delegate_noop!(Globals: ignore WlShm); delegate_noop!(MyWorld: ignore WlShm);
delegate_noop!(Globals: ignore ZwpLinuxDmabufV1); delegate_noop!(MyWorld: ignore ZwpLinuxDmabufV1);
delegate_noop!(Globals: ZwpRelativePointerManagerV1); delegate_noop!(MyWorld: ZwpRelativePointerManagerV1);
delegate_noop!(Globals: ignore dmabuf::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1); delegate_noop!(MyWorld: ignore dmabuf::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1);
delegate_noop!(Globals: XdgPositioner); delegate_noop!(MyWorld: XdgPositioner);
delegate_noop!(Globals: WlShmPool); delegate_noop!(MyWorld: WlShmPool);
delegate_noop!(Globals: WpViewporter); delegate_noop!(MyWorld: WpViewporter);
delegate_noop!(Globals: WpViewport); delegate_noop!(MyWorld: WpViewport);
delegate_noop!(Globals: ZxdgOutputManagerV1); delegate_noop!(MyWorld: ZxdgOutputManagerV1);
delegate_noop!(Globals: ZwpPointerConstraintsV1); delegate_noop!(MyWorld: ZwpPointerConstraintsV1);
delegate_noop!(Globals: ZwpTabletManagerV2); delegate_noop!(MyWorld: ZwpTabletManagerV2);
delegate_noop!(Globals: XdgActivationV1); delegate_noop!(MyWorld: XdgActivationV1);
delegate_noop!(Globals: ZxdgDecorationManagerV1); delegate_noop!(MyWorld: ZxdgDecorationManagerV1);
delegate_noop!(Globals: WpFractionalScaleManagerV1); delegate_noop!(MyWorld: WpFractionalScaleManagerV1);
delegate_noop!(Globals: ignore ZxdgToplevelDecorationV1); delegate_noop!(MyWorld: ignore ZxdgToplevelDecorationV1);
impl Dispatch<WlRegistry, GlobalListContents> for Globals { impl Dispatch<WlRegistry, GlobalListContents> for MyWorld {
fn event( fn event(
state: &mut Self, state: &mut Self,
_: &WlRegistry, _: &WlRegistry,
@ -174,7 +180,7 @@ impl Dispatch<WlRegistry, GlobalListContents> for Globals {
} }
} }
impl Dispatch<XdgWmBase, ()> for Globals { impl Dispatch<XdgWmBase, ()> for MyWorld {
fn event( fn event(
_: &mut Self, _: &mut Self,
base: &XdgWmBase, base: &XdgWmBase,
@ -189,7 +195,7 @@ impl Dispatch<XdgWmBase, ()> for Globals {
} }
} }
impl Dispatch<WlCallback, server::wl_callback::WlCallback> for Globals { impl Dispatch<WlCallback, server::wl_callback::WlCallback> for MyWorld {
fn event( fn event(
_: &mut Self, _: &mut Self,
_: &WlCallback, _: &WlCallback,
@ -206,12 +212,12 @@ impl Dispatch<WlCallback, server::wl_callback::WlCallback> for Globals {
macro_rules! push_events { macro_rules! push_events {
($type:ident) => { ($type:ident) => {
impl Dispatch<$type, ObjectKey> for Globals { impl Dispatch<$type, Entity> for MyWorld {
fn event( fn event(
state: &mut Self, state: &mut Self,
_: &$type, _: &$type,
event: <$type as Proxy>::Event, event: <$type as Proxy>::Event,
key: &ObjectKey, key: &Entity,
_: &Connection, _: &Connection,
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
) { ) {
@ -240,16 +246,16 @@ push_events!(ZwpLockedPointerV1);
push_events!(WpFractionalScaleV1); push_events!(WpFractionalScaleV1);
pub(crate) struct LateInitObjectKey<P: Proxy> { pub(crate) struct LateInitObjectKey<P: Proxy> {
key: OnceLock<ObjectKey>, key: OnceLock<Entity>,
queued_events: Mutex<Vec<P::Event>>, queued_events: Mutex<Vec<P::Event>>,
sender: Mutex<Option<mpsc::Sender<(ObjectKey, ObjectEvent)>>>, sender: Mutex<Option<mpsc::Sender<(Entity, ObjectEvent)>>>,
} }
impl<P: Proxy> LateInitObjectKey<P> impl<P: Proxy> LateInitObjectKey<P>
where where
P::Event: Into<ObjectEvent>, P::Event: Into<ObjectEvent>,
{ {
pub fn init(&self, key: ObjectKey) { pub fn init(&self, key: Entity) {
self.key.set(key).expect("Object key should not be set"); self.key.set(key).expect("Object key should not be set");
if let Some(sender) = self.sender.lock().unwrap().take() { if let Some(sender) = self.sender.lock().unwrap().take() {
for event in self.queued_events.lock().unwrap().drain(..) { for event in self.queued_events.lock().unwrap().drain(..) {
@ -266,7 +272,7 @@ where
} }
} }
fn push_or_queue_event(&self, state: &mut Globals, event: P::Event) { fn push_or_queue_event(&self, state: &mut MyWorld, event: P::Event) {
if let Some(key) = self.key.get().copied() { if let Some(key) = self.key.get().copied() {
state.events.push((key, event.into())); state.events.push((key, event.into()));
} else { } else {
@ -282,7 +288,7 @@ where
} }
impl<P: Proxy> std::ops::Deref for LateInitObjectKey<P> { impl<P: Proxy> std::ops::Deref for LateInitObjectKey<P> {
type Target = ObjectKey; type Target = Entity;
#[track_caller] #[track_caller]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -290,19 +296,19 @@ impl<P: Proxy> std::ops::Deref for LateInitObjectKey<P> {
} }
} }
impl Dispatch<ZwpTabletSeatV2, ObjectKey> for Globals { impl Dispatch<ZwpTabletSeatV2, Entity> for MyWorld {
fn event( fn event(
state: &mut Self, state: &mut Self,
_: &ZwpTabletSeatV2, _: &ZwpTabletSeatV2,
event: <ZwpTabletSeatV2 as Proxy>::Event, event: <ZwpTabletSeatV2 as Proxy>::Event,
key: &ObjectKey, key: &Entity,
_: &Connection, _: &Connection,
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
) { ) {
state.events.push((*key, event.into())); state.events.push((*key, event.into()));
} }
event_created_child!(Globals, ZwpTabletSeatV2, [ event_created_child!(MyWorld, ZwpTabletSeatV2, [
EVT_TABLET_ADDED_OPCODE => (ZwpTabletV2, LateInitObjectKey::new()), EVT_TABLET_ADDED_OPCODE => (ZwpTabletV2, LateInitObjectKey::new()),
EVT_PAD_ADDED_OPCODE => (ZwpTabletPadV2, LateInitObjectKey::new()), EVT_PAD_ADDED_OPCODE => (ZwpTabletPadV2, LateInitObjectKey::new()),
EVT_TOOL_ADDED_OPCODE => (ZwpTabletToolV2, LateInitObjectKey::new()) EVT_TOOL_ADDED_OPCODE => (ZwpTabletToolV2, LateInitObjectKey::new())
@ -311,7 +317,7 @@ impl Dispatch<ZwpTabletSeatV2, ObjectKey> for Globals {
macro_rules! push_or_queue_events { macro_rules! push_or_queue_events {
($type:ty) => { ($type:ty) => {
impl Dispatch<$type, LateInitObjectKey<$type>> for Globals { impl Dispatch<$type, LateInitObjectKey<$type>> for MyWorld {
fn event( fn event(
state: &mut Self, state: &mut Self,
_: &$type, _: &$type,
@ -331,7 +337,7 @@ push_or_queue_events!(ZwpTabletToolV2);
push_or_queue_events!(ZwpTabletPadRingV2); push_or_queue_events!(ZwpTabletPadRingV2);
push_or_queue_events!(ZwpTabletPadStripV2); push_or_queue_events!(ZwpTabletPadStripV2);
impl Dispatch<ZwpTabletPadV2, LateInitObjectKey<ZwpTabletPadV2>> for Globals { impl Dispatch<ZwpTabletPadV2, LateInitObjectKey<ZwpTabletPadV2>> for MyWorld {
fn event( fn event(
state: &mut Self, state: &mut Self,
_: &ZwpTabletPadV2, _: &ZwpTabletPadV2,
@ -343,12 +349,12 @@ impl Dispatch<ZwpTabletPadV2, LateInitObjectKey<ZwpTabletPadV2>> for Globals {
key.push_or_queue_event(state, event); key.push_or_queue_event(state, event);
} }
event_created_child!(Globals, ZwpTabletPadV2, [ event_created_child!(MyWorld, ZwpTabletPadV2, [
EVT_GROUP_OPCODE => (ZwpTabletPadGroupV2, LateInitObjectKey::new()) EVT_GROUP_OPCODE => (ZwpTabletPadGroupV2, LateInitObjectKey::new())
]); ]);
} }
impl Dispatch<ZwpTabletPadGroupV2, LateInitObjectKey<ZwpTabletPadGroupV2>> for Globals { impl Dispatch<ZwpTabletPadGroupV2, LateInitObjectKey<ZwpTabletPadGroupV2>> for MyWorld {
fn event( fn event(
state: &mut Self, state: &mut Self,
_: &ZwpTabletPadGroupV2, _: &ZwpTabletPadGroupV2,
@ -360,8 +366,169 @@ impl Dispatch<ZwpTabletPadGroupV2, LateInitObjectKey<ZwpTabletPadGroupV2>> for G
key.push_or_queue_event(state, event); key.push_or_queue_event(state, event);
} }
event_created_child!(Globals, ZwpTabletPadGroupV2, [ event_created_child!(MyWorld, ZwpTabletPadGroupV2, [
EVT_RING_OPCODE => (ZwpTabletPadRingV2, LateInitObjectKey::new()), EVT_RING_OPCODE => (ZwpTabletPadRingV2, LateInitObjectKey::new()),
EVT_STRIP_OPCODE => (ZwpTabletPadStripV2, LateInitObjectKey::new()) EVT_STRIP_OPCODE => (ZwpTabletPadStripV2, LateInitObjectKey::new())
]); ]);
} }
delegate_data_device!(MyWorld);
impl DataDeviceHandler for MyWorld {
fn selection(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
data_device: &wayland_client::protocol::wl_data_device::WlDataDevice,
) {
self.selection = Some(data_device.clone());
}
fn drop_performed(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
) {
}
fn motion(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
_: f64,
_: f64,
) {
}
fn leave(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
) {
}
fn enter(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_device::WlDataDevice,
_: f64,
_: f64,
_: &wayland_client::protocol::wl_surface::WlSurface,
) {
}
}
impl DataSourceHandler for MyWorld {
fn send_request(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
mime: String,
fd: smithay_client_toolkit::data_device_manager::WritePipe,
) {
self.selection_requests.push((mime, fd));
}
fn cancelled(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
self.selection_cancelled = true;
}
fn action(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
_: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
}
fn dnd_finished(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
}
fn dnd_dropped(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
) {
}
fn accept_mime(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &wayland_client::protocol::wl_data_source::WlDataSource,
_: Option<String>,
) {
}
}
impl DataOfferHandler for MyWorld {
fn selected_action(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &mut smithay_client_toolkit::data_device_manager::data_offer::DragOffer,
_: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
}
fn source_actions(
&mut self,
_: &wayland_client::Connection,
_: &wayland_client::QueueHandle<Self>,
_: &mut smithay_client_toolkit::data_device_manager::data_offer::DragOffer,
_: wayland_client::protocol::wl_data_device_manager::DndAction,
) {
}
}
delegate_activation!(MyWorld, ActivationData);
pub struct ActivationData {
window: x::Window,
data: RequestData,
}
impl ActivationData {
pub fn new(window: x::Window, data: RequestData) -> Self {
Self { window, data }
}
}
impl RequestDataExt for ActivationData {
fn app_id(&self) -> Option<&str> {
self.data.app_id()
}
fn seat_and_serial(&self) -> Option<(&wayland_client::protocol::wl_seat::WlSeat, u32)> {
self.data.seat_and_serial()
}
fn surface(&self) -> Option<&wayland_client::protocol::wl_surface::WlSurface> {
self.data.surface()
}
}
impl ActivationHandler for MyWorld {
type RequestData = ActivationData;
fn new_token(&mut self, token: String, data: &Self::RequestData) {
self.pending_activations.push((data.window, token));
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff