winit-core/window: add Window::request_ime_update
Allow updating IME state atomically to make it easier for platforms where it's atomic by its nature, like Wayland. The old API is marked as deprecated and is routed to the new atomic API. Co-authored-by: dcz <gilapfco.dcz@porcupinefactory.org>
This commit is contained in:
parent
fa0795a50c
commit
08907148ec
19 changed files with 866 additions and 222 deletions
|
|
@ -1416,7 +1416,7 @@ unsafe fn public_window_callback_inner(
|
|||
},
|
||||
|
||||
WM_IME_STARTCOMPOSITION => {
|
||||
let ime_allowed = userdata.window_state_lock().ime_allowed;
|
||||
let ime_allowed = userdata.window_state_lock().ime_capabilities.is_some();
|
||||
if ime_allowed {
|
||||
userdata.window_state_lock().ime_state = ImeState::Enabled;
|
||||
|
||||
|
|
@ -1429,7 +1429,7 @@ unsafe fn public_window_callback_inner(
|
|||
WM_IME_COMPOSITION => {
|
||||
let ime_allowed_and_composing = {
|
||||
let w = userdata.window_state_lock();
|
||||
w.ime_allowed && w.ime_state != ImeState::Disabled
|
||||
w.ime_capabilities.is_some() && w.ime_state != ImeState::Disabled
|
||||
};
|
||||
// Windows Hangul IME sends WM_IME_COMPOSITION after WM_IME_ENDCOMPOSITION, so
|
||||
// check whether composing.
|
||||
|
|
@ -1480,7 +1480,7 @@ unsafe fn public_window_callback_inner(
|
|||
WM_IME_ENDCOMPOSITION => {
|
||||
let ime_allowed_or_composing = {
|
||||
let w = userdata.window_state_lock();
|
||||
w.ime_allowed || w.ime_state != ImeState::Disabled
|
||||
w.ime_capabilities.is_some() || w.ime_state != ImeState::Disabled
|
||||
};
|
||||
if ime_allowed_or_composing {
|
||||
if userdata.window_state_lock().ime_state == ImeState::Preedit {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ impl ImeContext {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn system_has_ime() -> bool {
|
||||
pub unsafe fn system_has_ime() -> bool {
|
||||
unsafe { GetSystemMetrics(SM_IMMENABLED) != 0 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,8 +51,9 @@ use winit_core::error::RequestError;
|
|||
use winit_core::icon::{Icon, RgbaIcon};
|
||||
use winit_core::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider};
|
||||
use winit_core::window::{
|
||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
|
||||
WindowAttributes, WindowButtons, WindowId, WindowLevel,
|
||||
CursorGrabMode, ImeCapabilities, ImeRequest, ImeRequestError, ResizeDirection, Theme,
|
||||
UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId,
|
||||
WindowLevel,
|
||||
};
|
||||
|
||||
use crate::dark_mode::try_theme;
|
||||
|
|
@ -1008,26 +1009,64 @@ impl CoreWindow for Window {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_ime_cursor_area(&self, spot: Position, size: Size) {
|
||||
fn ime_capabilities(&self) -> Option<ImeCapabilities> {
|
||||
self.window_state.lock().unwrap().ime_capabilities
|
||||
}
|
||||
|
||||
fn request_ime_update(&self, request: ImeRequest) -> Result<(), ImeRequestError> {
|
||||
// NOTE: this is racy way of doing this, but unless we remove the `Send` from the `Window`
|
||||
// we can not do much about that.
|
||||
let cap = self.window_state.lock().unwrap().ime_capabilities;
|
||||
match &request {
|
||||
ImeRequest::Enable(..) if cap.is_some() => return Err(ImeRequestError::AlreadyEnabled),
|
||||
ImeRequest::Update(_) if cap.is_none() => return Err(ImeRequestError::NotEnabled),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let window = self.window;
|
||||
let state = self.window_state.clone();
|
||||
self.thread_executor.execute_in_thread(move || unsafe {
|
||||
let scale_factor = state.lock().unwrap().scale_factor;
|
||||
ImeContext::current(window.hwnd()).set_ime_cursor_area(spot, size, scale_factor);
|
||||
let hwnd = window.hwnd();
|
||||
let mut state = state.lock().unwrap();
|
||||
let (capabilities, request_data) = match &request {
|
||||
ImeRequest::Enable(enable) => {
|
||||
let capabilities = *enable.capabilities();
|
||||
state.ime_capabilities = Some(capabilities);
|
||||
ImeContext::set_ime_allowed(hwnd, true);
|
||||
(capabilities, enable.request_data())
|
||||
},
|
||||
ImeRequest::Update(request_data) => {
|
||||
if let Some(capabilities) = state.ime_capabilities {
|
||||
(capabilities, request_data)
|
||||
} else {
|
||||
warn!("ime update without IME enabled.");
|
||||
return;
|
||||
}
|
||||
},
|
||||
ImeRequest::Disable => {
|
||||
state.ime_capabilities = None;
|
||||
ImeContext::set_ime_allowed(window.hwnd(), false);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
if let Some((spot, size)) = request_data.cursor_area {
|
||||
if capabilities.contains(ImeCapabilities::CURSOR_AREA) {
|
||||
let scale_factor = state.scale_factor;
|
||||
ImeContext::current(window.hwnd()).set_ime_cursor_area(
|
||||
spot,
|
||||
size,
|
||||
scale_factor,
|
||||
);
|
||||
} else {
|
||||
warn!("discarding IME cursor area update without capability enabled.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn set_ime_allowed(&self, allowed: bool) {
|
||||
let window = self.window;
|
||||
let state = self.window_state.clone();
|
||||
self.thread_executor.execute_in_thread(move || unsafe {
|
||||
state.lock().unwrap().ime_allowed = allowed;
|
||||
ImeContext::set_ime_allowed(window.hwnd(), allowed);
|
||||
})
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_ime_purpose(&self, _purpose: ImePurpose) {}
|
||||
|
||||
fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let window = self.window;
|
||||
let active_window_handle = unsafe { GetActiveWindow() };
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
|||
use winit_core::icon::Icon;
|
||||
use winit_core::keyboard::ModifiersState;
|
||||
use winit_core::monitor::Fullscreen;
|
||||
use winit_core::window::{Theme, WindowAttributes};
|
||||
use winit_core::window::{ImeCapabilities, Theme, WindowAttributes};
|
||||
|
||||
use crate::{event_loop, util, SelectedCursor};
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ pub(crate) struct WindowState {
|
|||
pub window_flags: WindowFlags,
|
||||
|
||||
pub ime_state: ImeState,
|
||||
pub ime_allowed: bool,
|
||||
pub ime_capabilities: Option<ImeCapabilities>,
|
||||
|
||||
// Used by WM_NCACTIVATE, WM_SETFOCUS and WM_KILLFOCUS
|
||||
pub is_active: bool,
|
||||
|
|
@ -178,7 +178,7 @@ impl WindowState {
|
|||
window_flags: WindowFlags::empty(),
|
||||
|
||||
ime_state: ImeState::Disabled,
|
||||
ime_allowed: false,
|
||||
ime_capabilities: None,
|
||||
|
||||
is_active: false,
|
||||
is_focused: false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue