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
23 changes: 18 additions & 5 deletions crates/gpui_macos/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use std::{
ptr,
rc::Rc,
slice, str,
sync::{Arc, OnceLock},
sync::{Arc, OnceLock, atomic::AtomicBool},
};
use util::{
ResultExt,
Expand Down Expand Up @@ -179,6 +179,7 @@ pub(crate) struct MacPlatformState {
dock_menu: Option<id>,
menus: Option<Vec<OwnedMenu>>,
keyboard_mapper: Rc<MacKeyboardMapper>,
cursor_hidden: Arc<AtomicBool>,
}

impl MacPlatform {
Expand Down Expand Up @@ -215,6 +216,7 @@ impl MacPlatform {
on_thermal_state_change: None,
menus: None,
keyboard_mapper,
cursor_hidden: Arc::new(AtomicBool::new(false)),
}))
}

Expand Down Expand Up @@ -619,12 +621,22 @@ impl Platform for MacPlatform {
handle: AnyWindowHandle,
options: WindowParams,
) -> Result<Box<dyn PlatformWindow>> {
let renderer_context = self.0.lock().renderer_context.clone();
let (cursor_hidden, foreground_executor, background_executor, renderer_context) = {
let guard = self.0.lock();
(
guard.cursor_hidden.clone(),
guard.foreground_executor.clone(),
guard.background_executor.clone(),
guard.renderer_context.clone(),
)
};

Ok(Box::new(MacWindow::open(
handle,
options,
self.foreground_executor(),
self.background_executor(),
cursor_hidden,
foreground_executor,
background_executor,
renderer_context,
)))
}
Expand Down Expand Up @@ -979,8 +991,9 @@ impl Platform for MacPlatform {
/// Match cursor style to one of the styles available
/// in macOS's [NSCursor](https://developer.apple.com/documentation/appkit/nscursor).
fn set_cursor_style(&self, style: CursorStyle) {
let cursor_hidden = self.0.lock().cursor_hidden.clone();
unsafe {
set_active_window_cursor_style(style);
set_active_window_cursor_style(style, &cursor_hidden);
}
}

Expand Down
62 changes: 48 additions & 14 deletions crates/gpui_macos/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,17 +324,34 @@ pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -
/// This function is not thread safe. Callers must ensure this is called on the AppKit main
/// thread because it reads the active AppKit window and updates GPUI window state associated
/// with Objective-C objects.
pub(crate) unsafe fn set_active_window_cursor_style(style: CursorStyle) {
pub(crate) unsafe fn set_active_window_cursor_style(
style: CursorStyle,
cursor_hidden: &AtomicBool,
) {
// SAFETY: The caller guarantees AppKit main-thread access. The class check ensures the
// window has our WINDOW_STATE_IVAR before reading it.
unsafe {
let app = NSApplication::sharedApplication(nil);
let key_window: id = msg_send![app, keyWindow];
let main_window: id = msg_send![app, mainWindow];
if main_window.is_null() || !msg_send![main_window, isKindOfClass: WINDOW_CLASS] {
let active_window = if !key_window.is_null()
&& msg_send![key_window, isKindOfClass: WINDOW_CLASS]
{
Some(key_window)
} else if !main_window.is_null() && msg_send![main_window, isKindOfClass: WINDOW_CLASS] {
Some(main_window)
} else {
None
};

let Some(active_window) = active_window else {
if !matches!(style, CursorStyle::None) {
unhide_cursor(cursor_hidden);
}
return;
}
};

let window_state = get_window_state(&*main_window);
let window_state = get_window_state(&*active_window);
let mut window_state = window_state.lock();
if window_state.cursor_style != style {
window_state.cursor_style = style;
Expand All @@ -346,6 +363,22 @@ pub(crate) unsafe fn set_active_window_cursor_style(style: CursorStyle) {
}
}

/// Unhides the cursor if this GPUI platform instance has hidden it.
///
/// # Safety
///
/// Must be called on the AppKit main thread.
unsafe fn unhide_cursor(cursor_hidden: &AtomicBool) {
unsafe {
if cursor_hidden
.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
let _: () = msg_send![class!(NSCursor), unhide];
}
}
}

unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const Class {
unsafe {
let mut decl = ClassDecl::new(name, superclass).unwrap();
Expand Down Expand Up @@ -463,7 +496,7 @@ struct MacWindowState {
blurred_view: Option<id>,
background_appearance: WindowBackgroundAppearance,
cursor_style: CursorStyle,
cursor_hidden: bool,
cursor_hidden: Arc<AtomicBool>,
display_link: Option<DisplayLink>,
renderer: renderer::Renderer,
request_frame_callback: Option<Box<dyn FnMut(RequestFrameOptions)>>,
Expand Down Expand Up @@ -665,6 +698,7 @@ impl MacWindow {
tabbing_identifier,
..
}: WindowParams,
cursor_hidden: Arc<AtomicBool>,
foreground_executor: ForegroundExecutor,
background_executor: BackgroundExecutor,
renderer_context: renderer::Context,
Expand Down Expand Up @@ -782,7 +816,7 @@ impl MacWindow {
blurred_view: None,
background_appearance: WindowBackgroundAppearance::Opaque,
cursor_style: CursorStyle::Arrow,
cursor_hidden: false,
cursor_hidden,
display_link: None,
renderer: renderer::new_renderer(
renderer_context,
Expand Down Expand Up @@ -1816,18 +1850,21 @@ extern "C" fn reset_cursor_rects(this: &Object, _: Sel) {
let cursor_hidden;

{
let mut window_state = window_state.lock();
let window_state = window_state.lock();

if matches!(window_state.cursor_style, CursorStyle::None) {
if !window_state.cursor_hidden {
if window_state
.cursor_hidden
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
let _: () = msg_send![class!(NSCursor), hide];
window_state.cursor_hidden = true;
}
return;
}

cursor_style = window_state.cursor_style;
cursor_hidden = window_state.cursor_hidden;
cursor_hidden = window_state.cursor_hidden.clone();
};

let cursor: id = match cursor_style {
Expand Down Expand Up @@ -1867,10 +1904,7 @@ extern "C" fn reset_cursor_rects(this: &Object, _: Sel) {
CursorStyle::None => unreachable!(),
};

if cursor_hidden {
let _: () = msg_send![class!(NSCursor), unhide];
window_state.lock().cursor_hidden = false;
}
unhide_cursor(&cursor_hidden);

let bounds = NSView::bounds(this as *const Object as id);
let _: () = msg_send![this, addCursorRect: bounds cursor: cursor];
Expand Down
Loading