Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ Unreleased` header.
# Unreleased

- On Windows, macOS, X11, Wayland and Web, implement setting images as cursors. See the `custom_cursors.rs` example.
- Add `Window::set_custom_cursor`
- **Breaking:** Remove `Window::set_cursor_icon`
- Add `Window::set_cursor` which takes a `CursorIcon` or `CustomCursor`
- Add `CustomCursor`
- Add `CustomCursor::from_rgba` to allow creating cursor images from RGBA data.
- Add `CustomCursorExtWebSys::from_url` to allow loading cursor images from URLs.
Expand Down
2 changes: 1 addition & 1 deletion examples/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn main() -> Result<(), impl std::error::Error> {
..
} => {
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
window.set_cursor_icon(CURSORS[cursor_idx]);
window.set_cursor(CURSORS[cursor_idx]);
if cursor_idx < CURSORS.len() - 1 {
cursor_idx += 1;
} else {
Expand Down
6 changes: 3 additions & 3 deletions examples/custom_cursors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::{EventLoop, EventLoopWindowTarget},
keyboard::Key,
window::{CustomCursor, WindowBuilder},
window::{CursorIcon, CustomCursor, WindowBuilder},
};

fn decode_cursor<T>(bytes: &[u8], window_target: &EventLoopWindowTarget<T>) -> CustomCursor {
Expand Down Expand Up @@ -62,12 +62,12 @@ fn main() -> Result<(), impl std::error::Error> {
} => match key.as_ref() {
Key::Character("1") => {
log::debug!("Setting cursor to {:?}", cursor_idx);
window.set_custom_cursor(&custom_cursors[cursor_idx]);
window.set_cursor(custom_cursors[cursor_idx].clone());
cursor_idx = (cursor_idx + 1) % 2;
}
Key::Character("2") => {
log::debug!("Setting cursor icon to default");
window.set_cursor_icon(Default::default());
window.set_cursor(CursorIcon::default());
}
Key::Character("3") => {
cursor_visible = !cursor_visible;
Expand Down
2 changes: 1 addition & 1 deletion examples/multithreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn main() -> Result<(), impl std::error::Error> {
"1" => window.set_window_level(WindowLevel::AlwaysOnTop),
"2" => window.set_window_level(WindowLevel::AlwaysOnBottom),
"3" => window.set_window_level(WindowLevel::Normal),
"c" => window.set_cursor_icon(match state {
"c" => window.set_cursor(match state {
true => CursorIcon::Progress,
false => CursorIcon::Default,
}),
Expand Down
2 changes: 1 addition & 1 deletion examples/window_drag_resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn main() -> Result<(), impl std::error::Error> {

if new_location != cursor_location {
cursor_location = new_location;
window.set_cursor_icon(cursor_direction_icon(cursor_location))
window.set_cursor(cursor_direction_icon(cursor_location))
}
}
}
Expand Down
31 changes: 30 additions & 1 deletion src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::hash::Hasher;
use std::sync::Arc;
use std::{error::Error, hash::Hash};

use cursor_icon::CursorIcon;

use crate::event_loop::EventLoopWindowTarget;
use crate::platform_impl::{self, PlatformCustomCursor, PlatformCustomCursorBuilder};

Expand All @@ -11,8 +13,35 @@ pub const MAX_CURSOR_SIZE: u16 = 2048;

const PIXEL_SIZE: usize = 4;

/// See [`Window::set_cursor()`](crate::window::Window::set_cursor) for more details.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Cursor {
Icon(CursorIcon),
Custom(CustomCursor),
}

impl Default for Cursor {
fn default() -> Self {
Self::Icon(CursorIcon::default())
}
}

impl From<CursorIcon> for Cursor {
fn from(icon: CursorIcon) -> Self {
Self::Icon(icon)
}
}

impl From<CustomCursor> for Cursor {
fn from(custom: CustomCursor) -> Self {
Self::Custom(custom)
}
}

/// Use a custom image as a cursor (mouse pointer).
///
/// Is guaranteed to be cheap to clone.
///
/// ## Platform-specific
///
/// **Web**: Some browsers have limits on cursor sizes usually at 128x128.
Expand Down Expand Up @@ -44,7 +73,7 @@ const PIXEL_SIZE: usize = 4;
/// let custom_cursor = builder.build(&event_loop);
///
/// let window = Window::new(&event_loop).unwrap();
/// window.set_custom_cursor(&custom_cursor);
/// window.set_cursor(custom_cursor.clone());
/// ```
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct CustomCursor {
Expand Down
5 changes: 2 additions & 3 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use android_activity::{
use once_cell::sync::Lazy;

use crate::{
cursor::Cursor,
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error,
event::{self, Force, InnerSizeWriter, StartCause},
Expand Down Expand Up @@ -908,9 +909,7 @@ impl Window {

pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}

pub fn set_cursor_icon(&self, _: window::CursorIcon) {}

pub(crate) fn set_custom_cursor(&self, _: PlatformCustomCursor) {}
pub fn set_cursor(&self, _: Cursor) {}

pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
Expand Down
15 changes: 6 additions & 9 deletions src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ use super::app_state::EventWrapper;
use super::uikit::{UIApplication, UIScreen, UIScreenOverscanCompensation};
use super::view::{WinitUIWindow, WinitView, WinitViewController};
use crate::{
cursor::Cursor,
dpi::{self, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
error::{ExternalError, NotSupportedError, OsError as RootOsError},
event::{Event, WindowEvent},
icon::Icon,
platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations},
platform_impl::platform::{
app_state, monitor, EventLoopWindowTarget, Fullscreen, MonitorHandle, PlatformCustomCursor,
app_state, monitor, EventLoopWindowTarget, Fullscreen, MonitorHandle,
},
window::{
CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, UserAttentionType,
WindowAttributes, WindowButtons, WindowId as RootWindowId, WindowLevel,
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
WindowButtons, WindowId as RootWindowId, WindowLevel,
},
};

Expand Down Expand Up @@ -173,12 +174,8 @@ impl Inner {
self.view.contentScaleFactor() as _
}

pub fn set_cursor_icon(&self, _cursor: CursorIcon) {
debug!("`Window::set_cursor_icon` ignored on iOS")
}

pub(crate) fn set_custom_cursor(&self, _: PlatformCustomCursor) {
debug!("`Window::set_custom_cursor` ignored on iOS")
pub fn set_cursor(&self, _cursor: Cursor) {
debug!("`Window::set_cursor` ignored on iOS")
}

pub fn set_cursor_position(&self, _position: Position) -> Result<(), ExternalError> {
Expand Down
11 changes: 3 additions & 8 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
scancode::PhysicalKeyExtScancode,
},
window::{
ActivationToken, CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme,
ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme,
UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
},
};
Expand Down Expand Up @@ -422,13 +422,8 @@ impl Window {
}

#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
x11_or_wayland!(match self; Window(w) => w.set_cursor_icon(cursor))
}

#[inline]
pub(crate) fn set_custom_cursor(&self, cursor: PlatformCustomCursor) {
x11_or_wayland!(match self; Window(w) => w.set_custom_cursor(cursor))
pub fn set_cursor(&self, cursor: Cursor) {
x11_or_wayland!(match self; Window(w) => w.set_cursor(cursor))
}

#[inline]
Expand Down
21 changes: 9 additions & 12 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
use crate::event::{Ime, WindowEvent};
use crate::event_loop::AsyncRequestSerial;
use crate::platform_impl::{
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
PlatformIcon, PlatformSpecificWindowBuilderAttributes as PlatformAttributes,
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformIcon,
PlatformSpecificWindowBuilderAttributes as PlatformAttributes,
};
use crate::window::{
CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, UserAttentionType,
Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType,
WindowAttributes, WindowButtons, WindowLevel,
};

Expand Down Expand Up @@ -502,16 +502,13 @@ impl Window {
}

#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
self.window_state.lock().unwrap().set_cursor(cursor);
}
pub fn set_cursor(&self, cursor: Cursor) {
let window_state = &mut self.window_state.lock().unwrap();

#[inline]
pub(crate) fn set_custom_cursor(&self, cursor: PlatformCustomCursor) {
self.window_state
.lock()
.unwrap()
.set_custom_cursor(&cursor.0);
match cursor {
Cursor::Icon(icon) => window_state.set_cursor(icon),
Cursor::Custom(cursor) => window_state.set_custom_cursor(&cursor.inner.0),
}
}

#[inline]
Expand Down
45 changes: 24 additions & 21 deletions src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{
sync::{Arc, Mutex, MutexGuard},
};

use cursor_icon::CursorIcon;
use x11rb::{
connection::Connection,
properties::{WmHints, WmHintsState, WmSizeHints, WmSizeHintsSpecification},
Expand All @@ -21,6 +20,7 @@ use x11rb::{
};

use crate::{
cursor::Cursor,
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{ExternalError, NotSupportedError, OsError as RootOsError},
event::{Event, InnerSizeWriter, WindowEvent},
Expand All @@ -30,8 +30,8 @@ use crate::{
atoms::*, xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender,
X11Error,
},
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformCustomCursor,
PlatformIcon, PlatformSpecificWindowBuilderAttributes, VideoMode as PlatformVideoMode,
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError, PlatformIcon,
PlatformSpecificWindowBuilderAttributes, VideoMode as PlatformVideoMode,
},
window::{
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
Expand Down Expand Up @@ -1537,28 +1537,31 @@ impl UnownedWindow {
}

#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
let old_cursor = replace(
&mut *self.selected_cursor.lock().unwrap(),
SelectedCursor::Named(cursor),
);
pub fn set_cursor(&self, cursor: Cursor) {
match cursor {
Cursor::Icon(icon) => {
let old_cursor = replace(
&mut *self.selected_cursor.lock().unwrap(),
SelectedCursor::Named(icon),
);

#[allow(clippy::mutex_atomic)]
if SelectedCursor::Named(cursor) != old_cursor && *self.cursor_visible.lock().unwrap() {
self.xconn.set_cursor_icon(self.xwindow, Some(cursor));
}
}
#[allow(clippy::mutex_atomic)]
if SelectedCursor::Named(icon) != old_cursor && *self.cursor_visible.lock().unwrap()
{
self.xconn.set_cursor_icon(self.xwindow, Some(icon));
}
}
Cursor::Custom(cursor) => {
let new_cursor = unsafe { CustomCursor::new(&self.xconn, &cursor.inner.0) };

#[inline]
pub(crate) fn set_custom_cursor(&self, cursor: PlatformCustomCursor) {
let new_cursor = unsafe { CustomCursor::new(&self.xconn, &cursor.0) };
#[allow(clippy::mutex_atomic)]
if *self.cursor_visible.lock().unwrap() {
self.xconn.set_custom_cursor(self.xwindow, &new_cursor);
}

#[allow(clippy::mutex_atomic)]
if *self.cursor_visible.lock().unwrap() {
self.xconn.set_custom_cursor(self.xwindow, &new_cursor);
*self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(new_cursor);
}
}

*self.selected_cursor.lock().unwrap() = SelectedCursor::Custom(new_cursor);
}

#[inline]
Expand Down
31 changes: 17 additions & 14 deletions src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::ops;
use std::sync::{Mutex, MutexGuard};

use crate::{
cursor::Cursor,
dpi::{
LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size, Size::Logical,
},
Expand All @@ -20,11 +21,11 @@ use crate::{
monitor::{self, MonitorHandle, VideoMode},
view::WinitView,
window_delegate::WinitWindowDelegate,
Fullscreen, OsError, PlatformCustomCursor,
Fullscreen, OsError,
},
window::{
CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, UserAttentionType,
WindowAttributes, WindowButtons, WindowId as RootWindowId, WindowLevel,
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
WindowButtons, WindowId as RootWindowId, WindowLevel,
},
};
use core_graphics::display::{CGDisplay, CGPoint};
Expand Down Expand Up @@ -795,17 +796,19 @@ impl WinitWindow {
buttons
}

pub fn set_cursor_icon(&self, icon: CursorIcon) {
let view = self.view();
view.set_cursor_icon(cursor_from_icon(icon));
self.invalidateCursorRectsForView(&view);
}

#[inline]
pub(crate) fn set_custom_cursor(&self, cursor: PlatformCustomCursor) {
let view = self.view();
view.set_cursor_icon(cursor.0.clone());
self.invalidateCursorRectsForView(&view);
pub fn set_cursor(&self, cursor: Cursor) {
match cursor {
Cursor::Icon(icon) => {
let view = self.view();
view.set_cursor_icon(cursor_from_icon(icon));
self.invalidateCursorRectsForView(&view);
}
Cursor::Custom(cursor) => {
let view = self.view();
view.set_cursor_icon(cursor.inner.0.clone());
self.invalidateCursorRectsForView(&view);
}
}
}

#[inline]
Expand Down
9 changes: 4 additions & 5 deletions src/platform_impl/orbital/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
};

use crate::{
cursor::Cursor,
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error,
platform_impl::Fullscreen,
Expand All @@ -12,8 +13,8 @@ use crate::{
};

use super::{
EventLoopWindowTarget, MonitorHandle, PlatformCustomCursor,
PlatformSpecificWindowBuilderAttributes, RedoxSocket, TimeSocket, WindowId, WindowProperties,
EventLoopWindowTarget, MonitorHandle, PlatformSpecificWindowBuilderAttributes, RedoxSocket,
TimeSocket, WindowId, WindowProperties,
};

// These values match the values uses in the `window_new` function in orbital:
Expand Down Expand Up @@ -350,9 +351,7 @@ impl Window {
pub fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}

#[inline]
pub fn set_cursor_icon(&self, _: window::CursorIcon) {}

pub(crate) fn set_custom_cursor(&self, _: PlatformCustomCursor) {}
pub fn set_cursor(&self, _: Cursor) {}

#[inline]
pub fn set_cursor_position(&self, _: Position) -> Result<(), error::ExternalError> {
Expand Down
Loading