mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
macOS set_ime_position
fixes (#2180)
* Use NSView's inputContext instead of creating our own This means that `set_ime_position` now properly invalidates the character coordinates. * Make `set_ime_position` robust against moving windows
This commit is contained in:
parent
a438091266
commit
e22c76b3ac
|
@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- macOS: Remove the need to call `set_ime_position` after moving the window.
|
||||||
- Added `Window::is_visible`.
|
- Added `Window::is_visible`.
|
||||||
- Added `Window::is_resizable`.
|
- Added `Window::is_resizable`.
|
||||||
- Added `Window::is_decorated`.
|
- Added `Window::is_decorated`.
|
||||||
|
|
|
@ -147,12 +147,6 @@ pub unsafe fn superclass(this: &Object) -> &Class {
|
||||||
&*superclass
|
&*superclass
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn create_input_context(view: id) -> IdRef {
|
|
||||||
let input_context: id = msg_send![class!(NSTextInputContext), alloc];
|
|
||||||
let input_context: id = msg_send![input_context, initWithClient: view];
|
|
||||||
IdRef::new(input_context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub unsafe fn open_emoji_picker() {
|
pub unsafe fn open_emoji_picker() {
|
||||||
let () = msg_send![NSApp(), orderFrontCharacterPalette: nil];
|
let () = msg_send![NSApp(), orderFrontCharacterPalette: nil];
|
||||||
|
|
|
@ -53,7 +53,8 @@ impl Default for CursorState {
|
||||||
pub(super) struct ViewState {
|
pub(super) struct ViewState {
|
||||||
ns_window: id,
|
ns_window: id,
|
||||||
pub cursor_state: Arc<Mutex<CursorState>>,
|
pub cursor_state: Arc<Mutex<CursorState>>,
|
||||||
ime_spot: Option<(f64, f64)>,
|
/// The position of the candidate window.
|
||||||
|
ime_position: LogicalPosition<f64>,
|
||||||
raw_characters: Option<String>,
|
raw_characters: Option<String>,
|
||||||
pub(super) modifiers: ModifiersState,
|
pub(super) modifiers: ModifiersState,
|
||||||
tracking_rect: Option<NSInteger>,
|
tracking_rect: Option<NSInteger>,
|
||||||
|
@ -71,7 +72,8 @@ pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) {
|
||||||
let state = ViewState {
|
let state = ViewState {
|
||||||
ns_window,
|
ns_window,
|
||||||
cursor_state,
|
cursor_state,
|
||||||
ime_spot: None,
|
// By default, open the candidate window in the top left corner
|
||||||
|
ime_position: LogicalPosition::new(0.0, 0.0),
|
||||||
raw_characters: None,
|
raw_characters: None,
|
||||||
modifiers: Default::default(),
|
modifiers: Default::default(),
|
||||||
tracking_rect: None,
|
tracking_rect: None,
|
||||||
|
@ -87,14 +89,11 @@ pub fn new_view(ns_window: id) -> (IdRef, Weak<Mutex<CursorState>>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_ime_position(ns_view: id, input_context: id, x: f64, y: f64) {
|
pub unsafe fn set_ime_position(ns_view: id, position: LogicalPosition<f64>) {
|
||||||
let state_ptr: *mut c_void = *(*ns_view).get_mut_ivar("winitState");
|
let state_ptr: *mut c_void = *(*ns_view).get_mut_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
let state = &mut *(state_ptr as *mut ViewState);
|
||||||
let content_rect =
|
state.ime_position = position;
|
||||||
NSWindow::contentRectForFrameRect_(state.ns_window, NSWindow::frame(state.ns_window));
|
let input_context: id = msg_send![ns_view, inputContext];
|
||||||
let base_x = content_rect.origin.x as f64;
|
|
||||||
let base_y = (content_rect.origin.y + content_rect.size.height) as f64;
|
|
||||||
state.ime_spot = Some((base_x + x, base_y - y));
|
|
||||||
let _: () = msg_send![input_context, invalidateCharacterCoordinates];
|
let _: () = msg_send![input_context, invalidateCharacterCoordinates];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,15 +479,16 @@ extern "C" fn first_rect_for_character_range(
|
||||||
unsafe {
|
unsafe {
|
||||||
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
let state_ptr: *mut c_void = *this.get_ivar("winitState");
|
||||||
let state = &mut *(state_ptr as *mut ViewState);
|
let state = &mut *(state_ptr as *mut ViewState);
|
||||||
let (x, y) = state.ime_spot.unwrap_or_else(|| {
|
let content_rect =
|
||||||
let content_rect = NSWindow::contentRectForFrameRect_(
|
NSWindow::contentRectForFrameRect_(state.ns_window, NSWindow::frame(state.ns_window));
|
||||||
state.ns_window,
|
let base_x = content_rect.origin.x as f64;
|
||||||
NSWindow::frame(state.ns_window),
|
let base_y = (content_rect.origin.y + content_rect.size.height) as f64;
|
||||||
);
|
let x = base_x + state.ime_position.x;
|
||||||
let x = content_rect.origin.x;
|
let y = base_y - state.ime_position.y;
|
||||||
let y = util::bottom_left_to_top_left(content_rect);
|
// This is not ideal: We _should_ return a different position based on
|
||||||
(x, y)
|
// the currently selected character (which varies depending on the type
|
||||||
});
|
// and size of the character), but in the current `winit` API there is
|
||||||
|
// no way to express this. Same goes for the `NSSize`.
|
||||||
NSRect::new(NSPoint::new(x as _, y as _), NSSize::new(0.0, 0.0))
|
NSRect::new(NSPoint::new(x as _, y as _), NSSize::new(0.0, 0.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,7 +363,6 @@ impl Drop for SharedStateMutexGuard<'_> {
|
||||||
pub struct UnownedWindow {
|
pub struct UnownedWindow {
|
||||||
pub ns_window: IdRef, // never changes
|
pub ns_window: IdRef, // never changes
|
||||||
pub ns_view: IdRef, // never changes
|
pub ns_view: IdRef, // never changes
|
||||||
input_context: IdRef, // never changes
|
|
||||||
shared_state: Arc<Mutex<SharedState>>,
|
shared_state: Arc<Mutex<SharedState>>,
|
||||||
decorations: AtomicBool,
|
decorations: AtomicBool,
|
||||||
cursor_state: Weak<Mutex<CursorState>>,
|
cursor_state: Weak<Mutex<CursorState>>,
|
||||||
|
@ -398,8 +397,6 @@ impl UnownedWindow {
|
||||||
ns_window.setInitialFirstResponder_(*ns_view);
|
ns_window.setInitialFirstResponder_(*ns_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_context = unsafe { util::create_input_context(*ns_view) };
|
|
||||||
|
|
||||||
let scale_factor = unsafe { NSWindow::backingScaleFactor(*ns_window) as f64 };
|
let scale_factor = unsafe { NSWindow::backingScaleFactor(*ns_window) as f64 };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -442,7 +439,6 @@ impl UnownedWindow {
|
||||||
let window = Arc::new(UnownedWindow {
|
let window = Arc::new(UnownedWindow {
|
||||||
ns_view,
|
ns_view,
|
||||||
ns_window,
|
ns_window,
|
||||||
input_context,
|
|
||||||
shared_state: Arc::new(Mutex::new(win_attribs.into())),
|
shared_state: Arc::new(Mutex::new(win_attribs.into())),
|
||||||
decorations: AtomicBool::new(decorations),
|
decorations: AtomicBool::new(decorations),
|
||||||
cursor_state,
|
cursor_state,
|
||||||
|
@ -1046,14 +1042,7 @@ impl UnownedWindow {
|
||||||
pub fn set_ime_position(&self, spot: Position) {
|
pub fn set_ime_position(&self, spot: Position) {
|
||||||
let scale_factor = self.scale_factor();
|
let scale_factor = self.scale_factor();
|
||||||
let logical_spot = spot.to_logical(scale_factor);
|
let logical_spot = spot.to_logical(scale_factor);
|
||||||
unsafe {
|
unsafe { view::set_ime_position(*self.ns_view, logical_spot) };
|
||||||
view::set_ime_position(
|
|
||||||
*self.ns_view,
|
|
||||||
*self.input_context,
|
|
||||||
logical_spot.x,
|
|
||||||
logical_spot.y,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in a new issue