Pointer
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user