use crate::input::Window;
use crate::input::mouse::{MouseWindowLocation, Shared};
use std::ffi::c_void;
use std::ptr::NonNull;
use std::sync::{Arc, Mutex, OnceLock, Weak};
use wayland_client::backend::ObjectId;
#[derive(Debug)]
pub(super) struct PlatformCoalescedMouse {}
#[derive(Default)]
struct MouseState {
shareds: Vec<Weak<Shared>>,
recent_x_pos: Option<f64>,
recent_y_pos: Option<f64>,
recent_window_width: Option<i32>,
recent_window_height: Option<i32>,
recent_window: Option<ObjectId>,
}
impl MouseState {
fn apply_all<F: Fn(&Shared)>(&mut self, f: F) {
self.shareds.retain(|shared| {
if let Some(shared) = shared.upgrade() {
f(&shared);
true
} else {
false
}
})
}
fn send_events_if_needed(&mut self) {
if let (
Some(recent_window_width),
Some(recent_window_height),
Some(recent_x_pos),
Some(recent_y_pos),
) = (
self.recent_window_width,
self.recent_window_height,
self.recent_x_pos,
self.recent_y_pos,
) {
let window = match self.recent_window.as_ref() {
None => None,
Some(object_id) => NonNull::new(object_id.protocol_id() as *mut c_void).map(Window),
};
let pos = MouseWindowLocation::new(
recent_x_pos,
recent_y_pos,
recent_window_width as f64,
recent_window_height as f64,
window,
);
self.apply_all(|shared| {
shared.set_window_location(pos);
})
}
}
}
pub fn motion_event(_time: u32, surface_x: f64, surface_y: f64) {
let mut lock = MOUSE_STATE.get_or_init(Mutex::default).lock().unwrap();
lock.recent_x_pos = Some(surface_x);
lock.recent_y_pos = Some(surface_y);
lock.send_events_if_needed();
}
pub fn xdg_toplevel_configure_event(width: i32, height: i32) {
let mut lock = MOUSE_STATE.get_or_init(Mutex::default).lock().unwrap();
lock.recent_window_width = Some(width);
lock.recent_window_height = Some(height);
lock.send_events_if_needed();
}
pub fn button_event(_time: u32, button: u32, state: u32, window: ObjectId) {
let down = state != 0;
let btn_code = match button {
0x110 => 0, 0x111 => 1, 0x112 => 2, 0x113 => 3, 0x114 => 4, 0x115 => 5, 0x116 => 6, 0x117 => 7, 0x118 => 8,
0x119 => 9,
_ => {
logwise::warn_sync!("Unknown button code: {button}", button = button);
return;
}
};
MOUSE_STATE
.get_or_init(Mutex::default)
.lock()
.unwrap()
.apply_all(|shared| {
shared.set_key_state(btn_code, down, window.protocol_id() as *mut c_void);
});
crate::input::keyboard::linux::ax::ax_mouse();
}
pub fn axis_event(_time: u32, axis: u32, value: f64, window: ObjectId) {
if axis == 0 {
MOUSE_STATE
.get_or_init(Mutex::default)
.lock()
.unwrap()
.apply_all(|shared| {
shared.add_scroll_delta(0.0, value, window.protocol_id() as *mut c_void);
})
} else {
MOUSE_STATE
.get_or_init(Mutex::default)
.lock()
.unwrap()
.apply_all(|shared| {
shared.add_scroll_delta(value, 0.0, window.protocol_id() as *mut c_void);
})
}
}
static MOUSE_STATE: OnceLock<Mutex<MouseState>> = OnceLock::new();
impl PlatformCoalescedMouse {
pub async fn new(shared: &Arc<Shared>) -> Self {
MOUSE_STATE
.get_or_init(Mutex::default)
.lock()
.unwrap()
.shareds
.push(Arc::downgrade(shared));
PlatformCoalescedMouse {}
}
}