Skip to content

Commit aef6cfa

Browse files
committed
added mouse cursor support to macos via macos/window
1 parent acdd9b6 commit aef6cfa

4 files changed

Lines changed: 99 additions & 1 deletion

File tree

src/macos/cursor.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use cocoa::base::id;
2+
use objc::{runtime::Sel, msg_send, sel, sel_impl, class};
3+
4+
use crate::MouseCursor;
5+
6+
#[derive(Debug)]
7+
pub enum Cursor {
8+
Native(&'static str),
9+
Undocumented(&'static str),
10+
}
11+
12+
impl From<MouseCursor> for Cursor {
13+
fn from(cursor: MouseCursor) -> Self {
14+
match cursor {
15+
MouseCursor::Default => Cursor::Native("arrowCursor"),
16+
MouseCursor::Pointer => Cursor::Native("pointingHandCursor"),
17+
MouseCursor::Hand => Cursor::Native("openHandCursor"),
18+
MouseCursor::HandGrabbing => Cursor::Native("closedHandCursor"),
19+
MouseCursor::Text => Cursor::Native("IBeamCursor"),
20+
MouseCursor::VerticalText => Cursor::Native("IBeamCursorForVerticalLayout"),
21+
MouseCursor::Copy => Cursor::Native("dragCopyCursor"),
22+
MouseCursor::Alias => Cursor::Native("dragLinkCursor"),
23+
MouseCursor::NotAllowed | MouseCursor::PtrNotAllowed => {
24+
Cursor::Native("operationNotAllowedCursor")
25+
}
26+
// MouseCursor:: => Cursor::Native("contextualMenuCursor"),
27+
MouseCursor::Crosshair => Cursor::Native("crosshairCursor"),
28+
MouseCursor::EResize => Cursor::Native("resizeRightCursor"),
29+
MouseCursor::NResize => Cursor::Native("resizeUpCursor"),
30+
MouseCursor::WResize => Cursor::Native("resizeLeftCursor"),
31+
MouseCursor::SResize => Cursor::Native("resizeDownCursor"),
32+
MouseCursor::EwResize | MouseCursor::ColResize => Cursor::Native("resizeLeftRightCursor"),
33+
MouseCursor::NsResize | MouseCursor::RowResize => Cursor::Native("resizeUpDownCursor"),
34+
35+
MouseCursor::Help => Cursor::Undocumented("_helpCursor"),
36+
MouseCursor::ZoomIn => Cursor::Undocumented("_zoomInCursor"),
37+
MouseCursor::ZoomOut => Cursor::Undocumented("_zoomOutCursor"),
38+
MouseCursor::NeResize => Cursor::Undocumented("_windowResizeNorthEastCursor"),
39+
MouseCursor::NwResize => Cursor::Undocumented("_windowResizeNorthWestCursor"),
40+
MouseCursor::SeResize => Cursor::Undocumented("_windowResizeSouthEastCursor"),
41+
MouseCursor::SwResize => Cursor::Undocumented("_windowResizeSouthWestCursor"),
42+
MouseCursor::NeswResize => Cursor::Undocumented("_windowResizeNorthEastSouthWestCursor"),
43+
MouseCursor::NwseResize => Cursor::Undocumented("_windowResizeNorthWestSouthEastCursor"),
44+
45+
MouseCursor::Working | MouseCursor::PtrWorking => {
46+
Cursor::Undocumented("busyButClickableCursor")
47+
}
48+
49+
_ => Cursor::Native("arrowCursor"),
50+
51+
// MouseCursor::Hidden => todo!(),
52+
// MouseCursor::Move => todo!(),
53+
// MouseCursor::AllScroll => todo!(),
54+
// MouseCursor::Cell => todo!(),
55+
}
56+
}
57+
}
58+
59+
impl Cursor {
60+
pub unsafe fn load(&self) -> id {
61+
match self {
62+
Cursor::Native(cursor_name) => {
63+
let sel = Sel::register(cursor_name);
64+
msg_send![class!(NSCursor), performSelector: sel]
65+
}
66+
Cursor::Undocumented(cursor_name) => {
67+
let class = class!(NSCursor);
68+
let sel = Sel::register(cursor_name);
69+
let sel = if msg_send![class, respondsToSelector: sel] {
70+
sel
71+
} else {
72+
sel!(arrowCursor)
73+
};
74+
msg_send![class, performSelector: sel]
75+
}
76+
}
77+
}
78+
}

src/macos/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod keyboard;
22
mod view;
33
mod window;
4+
mod cursor;
45

56
pub use window::*;

src/macos/window.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ use objc::{msg_send, runtime::Object, sel, sel_impl};
2020
use raw_window_handle::{AppKitHandle, HasRawWindowHandle, RawWindowHandle};
2121

2222
use crate::{
23-
Event, EventStatus, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
23+
Event, EventStatus, MouseCursor, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
2424
WindowScalePolicy,
2525
};
2626

27+
use super::cursor::Cursor;
2728
use super::keyboard::KeyboardState;
2829
use super::view::{create_view, BASEVIEW_STATE_IVAR};
2930

@@ -302,6 +303,18 @@ impl Window {
302303
self.close_requested = true;
303304
}
304305

306+
pub fn set_mouse_cursor(&self, cursor: MouseCursor) {
307+
let native_cursor = Cursor::from(cursor);
308+
unsafe {
309+
let bounds: NSRect = msg_send![self.ns_view as id, bounds];
310+
let cursor = native_cursor.load();
311+
let _: () = msg_send![self.ns_view as id,
312+
addCursorRect:bounds
313+
cursor:cursor
314+
];
315+
}
316+
}
317+
305318
#[cfg(feature = "opengl")]
306319
pub fn gl_context(&self) -> Option<&GlContext> {
307320
self.gl_context.as_ref()

src/window.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
44

55
use crate::event::{Event, EventStatus};
66
use crate::window_open_options::WindowOpenOptions;
7+
use crate::MouseCursor;
78

89
#[cfg(target_os = "macos")]
910
use crate::macos as platform;
@@ -98,6 +99,11 @@ impl<'a> Window<'a> {
9899
self.window.close();
99100
}
100101

102+
/// Set the cursor to the given cursor type
103+
pub fn set_mouse_cursor(&self, cursor: MouseCursor) {
104+
self.window.set_mouse_cursor(cursor);
105+
}
106+
101107
/// If provided, then an OpenGL context will be created for this window. You'll be able to
102108
/// access this context through [crate::Window::gl_context].
103109
#[cfg(feature = "opengl")]

0 commit comments

Comments
 (0)