Skip to content

Commit

Permalink
Client side delegate
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Feb 16, 2024
1 parent 9cd9b40 commit 31cae98
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 27 deletions.
103 changes: 103 additions & 0 deletions wayland-client/examples/delegated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#![allow(clippy::single_match)]

use wayland_client::{
protocol::{
wl_compositor::{self, WlCompositor},
wl_display::{self, WlDisplay},
wl_registry::{self, WlRegistry},
},
Connection, Dispatch, Proxy, QueueHandle,
};

mod delegated {
use super::*;

pub trait RegistryHandler: 'static {
fn state(&mut self) -> &mut Registry;

Check warning on line 16 in wayland-client/examples/delegated.rs

View workflow job for this annotation

GitHub Actions / coverage-main

method `state` is never used
fn new_global(&mut self, name: u32, interface: &str, version: u32);
}

pub struct Registry {
wl_registry: WlRegistry,
}

impl Registry {
pub fn new<D: RegistryHandler>(qh: &QueueHandle<D>, display: &WlDisplay) -> Self {
let data = qh.make_data::<WlRegistry, _, Self>(());

let wl_registry =
display.send_constructor(wl_display::Request::GetRegistry {}, data).unwrap();

Self { wl_registry }
}

pub fn wl_registry(&self) -> WlRegistry {
self.wl_registry.clone()
}
}

impl<D: RegistryHandler> Dispatch<WlRegistry, (), D> for Registry {
fn event(
state: &mut D,
_: &wl_registry::WlRegistry,
event: wl_registry::Event,
_: &(),
_: &Connection,
_: &QueueHandle<D>,
) {
if let wl_registry::Event::Global { name, interface, version } = event {
state.new_global(name, &interface, version);
}
}
}
}

struct AppData {
registry: delegated::Registry,
qh: QueueHandle<Self>,
}

impl delegated::RegistryHandler for AppData {
fn state(&mut self) -> &mut delegated::Registry {
&mut self.registry
}

fn new_global(&mut self, name: u32, interface: &str, version: u32) {
println!("[{}] {} (v{})", name, interface, version);

match interface {
"wl_compositor" => {
self.registry.wl_registry().bind(name, version, &self.qh, ());
}
_ => {}
}
}
}

impl Dispatch<WlCompositor, ()> for AppData {
fn event(
_state: &mut Self,
_proxy: &WlCompositor,
_event: wl_compositor::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
}
}

fn main() {
let conn = Connection::connect_to_env().unwrap();

let display = conn.display();

let mut event_queue = conn.new_event_queue::<AppData>();
let qh = event_queue.handle();

let registry = delegated::Registry::new(&qh, &display);

let mut app = AppData { registry, qh: qh.clone() };

println!("Advertized globals:");
event_queue.roundtrip(&mut app).unwrap();
}
41 changes: 24 additions & 17 deletions wayland-client/src/event_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ pub trait Dispatch<I, UserData, State = Self>
where
Self: Sized,
I: Proxy,
State: Dispatch<I, UserData, State>,
{
/// Called when an event from the server is processed
///
Expand Down Expand Up @@ -172,7 +171,7 @@ macro_rules! event_created_child {
match opcode {
$(
$opcode => {
qhandle.make_data::<$child_iface, _>({$child_udata})
qhandle.make_data::<$child_iface, _, $selftype>({$child_udata})
},
)*
_ => {
Expand Down Expand Up @@ -324,16 +323,17 @@ pub(crate) struct EventQueueInner<State> {
}

impl<State> EventQueueInner<State> {
pub(crate) fn enqueue_event<I, U>(
pub(crate) fn enqueue_event<I, U, DispatchTo>(
&mut self,
msg: Message<ObjectId, OwnedFd>,
odata: Arc<dyn ObjectData>,
) where
State: Dispatch<I, U> + 'static,
State: 'static,
DispatchTo: Dispatch<I, U, State> + 'static,
U: Send + Sync + 'static,
I: Proxy + 'static,
{
let func = queue_callback::<I, U, State>;
let func = queue_callback::<I, U, State, DispatchTo>;
self.queue.push_back(QueueEvent(func, msg, odata));
if self.freeze_count == 0 {
if let Some(waker) = self.waker.take() {
Expand Down Expand Up @@ -604,14 +604,16 @@ impl<State: 'static> QueueHandle<State> {
/// This creates an implementation of [`ObjectData`] fitting for direct use with `wayland-backend` APIs
/// that forwards all events to the event queue associated with this token, integrating the object into
/// the [`Dispatch`]-based logic of `wayland-client`.
pub fn make_data<I: Proxy + 'static, U: Send + Sync + 'static>(
///
/// Events will be dispatched via [`Dispatch`] to a `DelegateTo` generic type.
pub fn make_data<I: Proxy + 'static, U: Send + Sync + 'static, DelegateTo>(
&self,
user_data: U,
) -> Arc<dyn ObjectData>
where
State: Dispatch<I, U, State>,
DelegateTo: Dispatch<I, U, State> + 'static,
{
Arc::new(QueueProxyData::<I, U, State> {
Arc::new(QueueProxyData::<I, U, State, DelegateTo> {
handle: self.clone(),
udata: user_data,
_phantom: PhantomData,
Expand Down Expand Up @@ -643,7 +645,8 @@ impl<'a, State> Drop for QueueFreezeGuard<'a, State> {
fn queue_callback<
I: Proxy + 'static,
U: Send + Sync + 'static,
State: Dispatch<I, U, State> + 'static,
State,
DelegateTo: Dispatch<I, U, State> + 'static,
>(
handle: &Connection,
msg: Message<ObjectId, OwnedFd>,
Expand All @@ -653,21 +656,23 @@ fn queue_callback<
) -> Result<(), DispatchError> {
let (proxy, event) = I::parse_event(handle, msg)?;
let udata = odata.data_as_any().downcast_ref().expect("Wrong user_data value for object");
<State as Dispatch<I, U, State>>::event(data, &proxy, event, udata, handle, qhandle);
<DelegateTo as Dispatch<I, U, State>>::event(data, &proxy, event, udata, handle, qhandle);
Ok(())
}

/// The [`ObjectData`] implementation used by Wayland proxies, integrating with [`Dispatch`]
pub struct QueueProxyData<I: Proxy, U, State> {
pub struct QueueProxyData<I: Proxy, U, State, DispatchTo = State> {
handle: QueueHandle<State>,
/// The user data associated with this object
pub udata: U,
_phantom: PhantomData<fn(&I)>,
_phantom: PhantomData<fn(&I, &DispatchTo)>,
}

impl<I: Proxy + 'static, U: Send + Sync + 'static, State> ObjectData for QueueProxyData<I, U, State>
impl<I: Proxy + 'static, U: Send + Sync + 'static, State, DispatchTo> ObjectData
for QueueProxyData<I, U, State, DispatchTo>
where
State: Dispatch<I, U, State> + 'static,
State: 'static,
DispatchTo: Dispatch<I, U, State> + 'static,
{
fn event(
self: Arc<Self>,
Expand All @@ -678,9 +683,9 @@ where
.args
.iter()
.any(|arg| matches!(arg, Argument::NewId(id) if !id.is_null()))
.then(|| State::event_created_child(msg.opcode, &self.handle));
.then(|| DispatchTo::event_created_child(msg.opcode, &self.handle));

self.handle.inner.lock().unwrap().enqueue_event::<I, U>(msg, self.clone());
self.handle.inner.lock().unwrap().enqueue_event::<I, U, DispatchTo>(msg, self.clone());

new_data
}
Expand All @@ -692,7 +697,9 @@ where
}
}

impl<I: Proxy, U: std::fmt::Debug, State> std::fmt::Debug for QueueProxyData<I, U, State> {
impl<I: Proxy, U: std::fmt::Debug, State, DispatchTo> std::fmt::Debug
for QueueProxyData<I, U, State, DispatchTo>
{
#[cfg_attr(coverage, coverage(off))]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QueueProxyData").field("udata", &self.udata).finish()
Expand Down
5 changes: 4 additions & 1 deletion wayland-client/src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,10 @@ where
.inner
.lock()
.unwrap()
.enqueue_event::<wl_registry::WlRegistry, GlobalListContents>(msg, self.clone())
.enqueue_event::<wl_registry::WlRegistry, GlobalListContents, State>(
msg,
self.clone(),
)
}

// We do not create any objects in this event handler.
Expand Down
4 changes: 2 additions & 2 deletions wayland-scanner/src/client_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ fn gen_methods(interface: &Interface) -> TokenStream {
Request::#enum_variant {
#(#enum_args),*
},
qh.make_data::<super::#created_iface_mod::#created_iface_type, U>(udata),
qh.make_data::<super::#created_iface_mod::#created_iface_type, U, D>(udata),
).unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
}
Expand All @@ -284,7 +284,7 @@ fn gen_methods(interface: &Interface) -> TokenStream {
Request::#enum_variant {
#(#enum_args),*
},
qh.make_data::<I, U>(udata),
qh.make_data::<I, U, D>(udata),
).unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
}
Expand Down
12 changes: 6 additions & 6 deletions wayland-scanner/tests/scanner_assets/test-client-code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ pub mod wl_display {
) -> super::wl_callback::WlCallback {
self.send_constructor(
Request::Sync {},
qh.make_data::<super::wl_callback::WlCallback, U>(udata),
qh.make_data::<super::wl_callback::WlCallback, U, D>(udata),
)
.unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
Expand All @@ -306,7 +306,7 @@ pub mod wl_display {
) -> super::wl_registry::WlRegistry {
self.send_constructor(
Request::GetRegistry {},
qh.make_data::<super::wl_registry::WlRegistry, U>(udata),
qh.make_data::<super::wl_registry::WlRegistry, U, D>(udata),
)
.unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
Expand Down Expand Up @@ -560,7 +560,7 @@ pub mod wl_registry {
) -> I {
self.send_constructor(
Request::Bind { name, id: (I::interface(), version) },
qh.make_data::<I, U>(udata),
qh.make_data::<I, U, D>(udata),
)
.unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
Expand Down Expand Up @@ -1236,7 +1236,7 @@ pub mod test_global {
) -> super::secondary::Secondary {
self.send_constructor(
Request::GetSecondary {},
qh.make_data::<super::secondary::Secondary, U>(udata),
qh.make_data::<super::secondary::Secondary, U, D>(udata),
)
.unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
Expand All @@ -1251,7 +1251,7 @@ pub mod test_global {
) -> super::tertiary::Tertiary {
self.send_constructor(
Request::GetTertiary {},
qh.make_data::<super::tertiary::Tertiary, U>(udata),
qh.make_data::<super::tertiary::Tertiary, U, D>(udata),
)
.unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
Expand Down Expand Up @@ -1315,7 +1315,7 @@ pub mod test_global {
) -> super::quad::Quad {
self.send_constructor(
Request::NewidAndAllowNull { sec: sec.cloned(), ter: ter.clone() },
qh.make_data::<super::quad::Quad, U>(udata),
qh.make_data::<super::quad::Quad, U, D>(udata),
)
.unwrap_or_else(|_| Proxy::inert(self.backend.clone()))
}
Expand Down
2 changes: 1 addition & 1 deletion wayland-tests/tests/client_bad_requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn send_constructor_wrong_type() {
client
.event_queue
.handle()
.make_data::<wayc::protocol::wl_keyboard::WlKeyboard, _>(()),
.make_data::<wayc::protocol::wl_keyboard::WlKeyboard, _, ClientHandler>(()),
),
)
.unwrap();
Expand Down

0 comments on commit 31cae98

Please sign in to comment.