winit-core: move cursor

This commit is contained in:
Kirill Chibisov 2025-05-01 20:16:34 +09:00
parent cbb29ab526
commit 446482367b
8 changed files with 77 additions and 38 deletions

View file

@ -301,7 +301,7 @@ pub mod application;
pub mod changelog;
#[macro_use]
pub mod error;
mod cursor;
use winit_core::cursor;
pub mod event;
pub mod event_loop;
pub use winit_core::{icon, keyboard, monitor};

View file

@ -42,8 +42,8 @@ impl CustomCursor {
}
pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result<Retained<NSCursor>, RequestError> {
let width = cursor.width;
let height = cursor.height;
let width = cursor.width();
let height = cursor.height();
let bitmap = unsafe {
NSBitmapImageRep::initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel(
@ -60,15 +60,16 @@ pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result<Retained<NSCurso
32,
)
}.ok_or_else(|| os_error!("parent view should be installed in a window"))?;
let bitmap_data = unsafe { slice::from_raw_parts_mut(bitmap.bitmapData(), cursor.rgba.len()) };
bitmap_data.copy_from_slice(&cursor.rgba);
let bitmap_data =
unsafe { slice::from_raw_parts_mut(bitmap.bitmapData(), cursor.buffer().len()) };
bitmap_data.copy_from_slice(cursor.buffer());
let image = unsafe {
NSImage::initWithSize(NSImage::alloc(), NSSize::new(width.into(), height.into()))
};
unsafe { image.addRepresentation(&bitmap) };
let hotspot = NSPoint::new(cursor.hotspot_x as f64, cursor.hotspot_y as f64);
let hotspot = NSPoint::new(cursor.hotspot_x() as f64, cursor.hotspot_y() as f64);
Ok(NSCursor::initWithImage_hotSpot(NSCursor::alloc(), &image, hotspot))
}

View file

@ -39,14 +39,14 @@ impl CustomCursor {
let image = &image.0;
let (buffer, canvas) = pool
.create_buffer(
image.width as i32,
image.height as i32,
4 * (image.width as i32),
image.width() as i32,
image.height() as i32,
4 * (image.width() as i32),
Format::Argb8888,
)
.unwrap();
for (canvas_chunk, rgba) in canvas.chunks_exact_mut(4).zip(image.rgba.chunks_exact(4)) {
for (canvas_chunk, rgba) in canvas.chunks_exact_mut(4).zip(image.buffer().chunks_exact(4)) {
// Alpha in buffer is premultiplied.
let alpha = rgba[3] as f32 / 255.;
let r = (rgba[0] as f32 * alpha) as u32;
@ -59,10 +59,10 @@ impl CustomCursor {
CustomCursor {
buffer,
w: image.width as i32,
h: image.height as i32,
hotspot_x: image.hotspot_x as i32,
hotspot_y: image.hotspot_y as i32,
w: image.width() as i32,
h: image.height() as i32,
hotspot_x: image.hotspot_x() as i32,
hotspot_y: image.hotspot_y() as i32,
}
}
}

View file

@ -208,7 +208,7 @@ impl CustomCursor {
};
// Reverse RGBA order to BGRA.
cursor.rgba.chunks_mut(4).for_each(|chunk| {
cursor.buffer_mut().chunks_mut(4).for_each(|chunk| {
let chunk: &mut [u8; 4] = chunk.try_into().unwrap();
chunk[0..3].reverse();
@ -222,11 +222,11 @@ impl CustomCursor {
let cursor = event_loop
.xconn
.create_cursor_from_image(
cursor.width,
cursor.height,
cursor.hotspot_x,
cursor.hotspot_y,
&cursor.rgba,
cursor.width(),
cursor.height(),
cursor.hotspot_x(),
cursor.hotspot_y(),
cursor.buffer(),
)
.map_err(|err| os_error!(err))?;

View file

@ -24,9 +24,7 @@ use super::backend::Style;
use super::main_thread::{MainThreadMarker, MainThreadSafe};
use super::r#async::{AbortHandle, Abortable, DropAbortHandle, Notified, Notifier};
use super::ActiveEventLoop;
use crate::cursor::{
Cursor, CursorAnimation, CursorImage, CustomCursorProvider, CustomCursorSource,
};
use crate::cursor::{Cursor, CursorImage, CustomCursorProvider, CustomCursorSource};
use crate::platform::web::CustomCursorError;
#[derive(Clone, Debug)]
@ -48,7 +46,8 @@ impl CustomCursor {
from_url(UrlType::Plain(url), hotspot_x, hotspot_y),
false,
),
CustomCursorSource::Animation(CursorAnimation { duration, cursors }) => {
CustomCursorSource::Animation(animation) => {
let (duration, cursors) = animation.into_raw();
Self::build_spawn(
event_loop,
from_animation(event_loop.runner.main_thread(), duration, cursors.into_iter()),
@ -512,17 +511,17 @@ fn from_rgba(
fn new(array: Uint8ClampedArray, sw: u32) -> Result<ImageDataExt, JsValue>;
}
let array = Uint8Array::new_with_length(image.rgba.len() as u32);
array.copy_from(&image.rgba);
let array = Uint8Array::new_with_length(image.buffer().len() as u32);
array.copy_from(image.buffer());
let array = Uint8ClampedArray::new(&array);
ImageDataExt::new(array, image.width as u32)
ImageDataExt::new(array, image.width() as u32)
.map(JsValue::from)
.map(ImageData::unchecked_from_js)
};
#[cfg(not(target_feature = "atomics"))]
let result = ImageData::new_with_u8_clamped_array(
wasm_bindgen::Clamped(&image.rgba),
image.width as u32,
wasm_bindgen::Clamped(image.buffer()),
image.width() as u32,
);
let image_data = result.expect("found wrong image size");
@ -538,7 +537,10 @@ fn from_rgba(
.expect("unexpected exception in `createImageBitmap()`"),
);
let CursorImage { width, height, hotspot_x, hotspot_y, .. } = *image;
let width = image.width();
let height = image.height();
let hotspot_x = image.hotspot_x();
let hotspot_y = image.hotspot_y();
async move {
let bitmap: ImageBitmap =
bitmap.await.expect("found invalid state in `ImageData`").unchecked_into();

View file

@ -184,11 +184,11 @@ impl CustomCursorProvider for WinCursor {
impl WinCursor {
pub(crate) fn new(image: &CursorImage) -> Result<Self, RequestError> {
let mut bgra = image.rgba.clone();
let mut bgra = Vec::from(image.buffer());
bgra.chunks_exact_mut(4).for_each(|chunk| chunk.swap(0, 2));
let w = image.width as i32;
let h = image.height as i32;
let w = image.width() as i32;
let h = image.height() as i32;
unsafe {
let hdc_screen = GetDC(ptr::null_mut());
@ -215,8 +215,8 @@ impl WinCursor {
let icon_info = ICONINFO {
fIcon: 0,
xHotspot: image.hotspot_x as u32,
yHotspot: image.hotspot_y as u32,
xHotspot: image.hotspot_x() as u32,
yHotspot: image.hotspot_y() as u32,
hbmMask: hbm_mask,
hbmColor: hbm_color,
};

View file

@ -7,7 +7,7 @@ use std::time::Duration;
use cursor_icon::CursorIcon;
use crate::utils::{impl_dyn_casting, AsAny};
use crate::as_any::{impl_dyn_casting, AsAny};
/// The maximum width and height for a cursor when using [`CustomCursorSource::from_rgba`].
pub const MAX_CURSOR_SIZE: u16 = 2048;
@ -75,7 +75,7 @@ impl From<CustomCursor> for Cursor {
/// # }
/// ```
#[derive(Clone, Debug)]
pub struct CustomCursor(pub(crate) Arc<dyn CustomCursorProvider>);
pub struct CustomCursor(pub Arc<dyn CustomCursorProvider>);
pub trait CustomCursorProvider: AsAny + fmt::Debug + Send + Sync {
/// Whether a cursor was backed by animation.
@ -235,7 +235,6 @@ impl fmt::Display for BadAnimation {
impl Error for BadAnimation {}
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
#[allow(dead_code)]
pub struct CursorImage {
pub(crate) rgba: Vec<u8>,
pub(crate) width: u16,
@ -277,6 +276,30 @@ impl CursorImage {
Ok(CursorImage { rgba, width, height, hotspot_x, hotspot_y })
}
pub fn buffer(&self) -> &[u8] {
self.rgba.as_slice()
}
pub fn buffer_mut(&mut self) -> &mut [u8] {
self.rgba.as_mut_slice()
}
pub fn width(&self) -> u16 {
self.width
}
pub fn height(&self) -> u16 {
self.height
}
pub fn hotspot_x(&self) -> u16 {
self.hotspot_x
}
pub fn hotspot_y(&self) -> u16 {
self.hotspot_y
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -297,4 +320,16 @@ impl CursorAnimation {
Ok(Self { duration, cursors })
}
pub fn duration(&self) -> Duration {
self.duration
}
pub fn cursors(&self) -> &[CustomCursor] {
self.cursors.as_slice()
}
pub fn into_raw(self) -> (Duration, Vec<CustomCursor>) {
(self.duration, self.cursors)
}
}

View file

@ -1,5 +1,6 @@
#[macro_use]
pub mod as_any;
pub mod cursor;
pub mod icon;
pub mod keyboard;
pub mod monitor;