This commit is contained in:
2026-03-20 20:28:48 -04:00
parent f71e03317d
commit d79a3bb728
9 changed files with 702 additions and 52 deletions

View File

@@ -10,10 +10,10 @@ use raw_window_handle::{
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawDisplayHandle,
RawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle, WindowHandle,
};
use ruin_ui::{UiSize, WindowSpec};
use ruin_ui::{Point, PointerButton, PointerEvent, PointerEventKind, UiSize, WindowSpec};
use wayland_client::globals::{GlobalListContents, registry_queue_init};
use wayland_client::protocol::{wl_compositor, wl_registry, wl_surface};
use wayland_client::{Connection, Dispatch, Proxy, QueueHandle, delegate_noop};
use wayland_client::protocol::{wl_compositor, wl_pointer, wl_registry, wl_seat, wl_surface};
use wayland_client::{Connection, Dispatch, Proxy, QueueHandle, WEnum, delegate_noop};
use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
#[derive(Clone)]
@@ -67,10 +67,14 @@ struct State {
_xdg_surface: xdg_surface::XdgSurface,
_toplevel: xdg_toplevel::XdgToplevel,
_wm_base: xdg_wm_base::XdgWmBase,
_seat: wl_seat::WlSeat,
pointer: Option<wl_pointer::WlPointer>,
current_size: (u32, u32),
configured: bool,
pending_size: Option<(u32, u32)>,
needs_redraw: bool,
pointer_position: Option<Point>,
pending_pointer_events: Vec<PointerEvent>,
}
impl State {
@@ -86,6 +90,7 @@ impl WaylandWindow {
let qh = event_queue.handle();
let compositor: wl_compositor::WlCompositor = globals.bind(&qh, 4..=6, ())?;
let seat: wl_seat::WlSeat = globals.bind(&qh, 1..=9, ())?;
let wm_base: xdg_wm_base::XdgWmBase = globals.bind(&qh, 1..=6, ())?;
let surface = compositor.create_surface(&qh, ());
let xdg_surface = wm_base.get_xdg_surface(&surface, &qh, ());
@@ -127,10 +132,14 @@ impl WaylandWindow {
_xdg_surface: xdg_surface,
_toplevel: toplevel,
_wm_base: wm_base,
_seat: seat,
pointer: None,
current_size: (initial_width, initial_height),
configured: false,
pending_size: None,
needs_redraw: false,
pointer_position: None,
pending_pointer_events: Vec::new(),
},
})
}
@@ -273,6 +282,10 @@ impl WaylandWindow {
self.state.request_redraw();
}
pub fn drain_pointer_events(&mut self) -> Vec<PointerEvent> {
std::mem::take(&mut self.state.pending_pointer_events)
}
pub fn prepare_frame(&mut self) -> Option<FrameRequest> {
if !self.state.configured {
return None;
@@ -316,6 +329,97 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
delegate_noop!(State: ignore wl_compositor::WlCompositor);
delegate_noop!(State: ignore wl_surface::WlSurface);
impl Dispatch<wl_seat::WlSeat, ()> for State {
fn event(
state: &mut Self,
seat: &wl_seat::WlSeat,
event: wl_seat::Event,
_data: &(),
_conn: &Connection,
qh: &QueueHandle<Self>,
) {
if let wl_seat::Event::Capabilities { capabilities } = event {
let WEnum::Value(capabilities) = capabilities else {
return;
};
if capabilities.contains(wl_seat::Capability::Pointer) {
if state.pointer.is_none() {
state.pointer = Some(seat.get_pointer(qh, ()));
}
} else {
state.pointer = None;
state.pointer_position = None;
}
}
}
}
impl Dispatch<wl_pointer::WlPointer, ()> for State {
fn event(
state: &mut Self,
_pointer: &wl_pointer::WlPointer,
event: wl_pointer::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
match event {
wl_pointer::Event::Enter {
surface_x,
surface_y,
..
}
| wl_pointer::Event::Motion {
surface_x,
surface_y,
..
} => {
let position = Point::new(surface_x as f32, surface_y as f32);
state.pointer_position = Some(position);
state.pending_pointer_events.push(PointerEvent::new(
0,
position,
PointerEventKind::Move,
));
}
wl_pointer::Event::Leave { .. } => {
let position = state.pointer_position.unwrap_or(Point::new(-1.0, -1.0));
state.pending_pointer_events.push(PointerEvent::new(
0,
position,
PointerEventKind::LeaveWindow,
));
state.pointer_position = None;
}
wl_pointer::Event::Button {
button,
state: button_state,
..
} => {
let Some(position) = state.pointer_position else {
return;
};
if button != 0x110 {
return;
}
let kind = match button_state {
WEnum::Value(wl_pointer::ButtonState::Pressed) => PointerEventKind::Down {
button: PointerButton::Primary,
},
WEnum::Value(wl_pointer::ButtonState::Released) => PointerEventKind::Up {
button: PointerButton::Primary,
},
WEnum::Value(_) | WEnum::Unknown(_) => return,
};
state
.pending_pointer_events
.push(PointerEvent::new(0, position, kind));
}
_ => {}
}
}
}
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for State {
fn event(
_state: &mut Self,