winit-core/window: wrap ImeCapabilities in struct
To prevent user from using `::all()` and thus writing not forward compatible code wrap the bitflags struct and provide simpler interface to it.
This commit is contained in:
parent
08907148ec
commit
abed32eb80
6 changed files with 86 additions and 46 deletions
|
|
@ -669,7 +669,11 @@ impl WindowState {
|
||||||
let request_data = ImeRequestData::default()
|
let request_data = ImeRequestData::default()
|
||||||
.with_purpose(ImePurpose::Normal)
|
.with_purpose(ImePurpose::Normal)
|
||||||
.with_cursor_area(LogicalPosition { x: 0, y: 0 }.into(), IME_CURSOR_SIZE.into());
|
.with_cursor_area(LogicalPosition { x: 0, y: 0 }.into(), IME_CURSOR_SIZE.into());
|
||||||
let enable_request = ImeEnableRequest::new(ImeCapabilities::all(), request_data).unwrap();
|
let enable_request = ImeEnableRequest::new(
|
||||||
|
ImeCapabilities::new().with_purpose().with_cursor_area(),
|
||||||
|
request_data,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let enable_ime = ImeRequest::Enable(enable_request);
|
let enable_ime = ImeRequest::Enable(enable_request);
|
||||||
|
|
||||||
// Initial update
|
// Initial update
|
||||||
|
|
@ -714,8 +718,11 @@ impl WindowState {
|
||||||
.unwrap_or(LogicalPosition { x: 0, y: 0 }.into());
|
.unwrap_or(LogicalPosition { x: 0, y: 0 }.into());
|
||||||
let request_data =
|
let request_data =
|
||||||
ImeRequestData::default().with_cursor_area(cursor_pos, IME_CURSOR_SIZE.into());
|
ImeRequestData::default().with_cursor_area(cursor_pos, IME_CURSOR_SIZE.into());
|
||||||
let enable_request =
|
let enable_request = ImeEnableRequest::new(
|
||||||
ImeEnableRequest::new(ImeCapabilities::all(), request_data).unwrap();
|
ImeCapabilities::new().with_purpose().with_cursor_area(),
|
||||||
|
request_data,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
self.window.request_ime_update(ImeRequest::Enable(enable_request)).unwrap();
|
self.window.request_ime_update(ImeRequest::Enable(enable_request)).unwrap();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1698,7 +1698,7 @@ impl WindowDelegate {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((spot, size)) = request_data.cursor_area {
|
if let Some((spot, size)) = request_data.cursor_area {
|
||||||
if self.view().ime_capabilities().unwrap().contains(ImeCapabilities::CURSOR_AREA) {
|
if self.view().ime_capabilities().unwrap().cursor_area() {
|
||||||
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);
|
||||||
let logical_spot = NSPoint::new(logical_spot.x, logical_spot.y);
|
let logical_spot = NSPoint::new(logical_spot.x, logical_spot.y);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
//! The [`Window`] trait and associated types.
|
//! The [`Window`] trait and associated types.
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use bitflags::bitflags;
|
||||||
use cursor_icon::CursorIcon;
|
use cursor_icon::CursorIcon;
|
||||||
use dpi::{
|
use dpi::{
|
||||||
LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size,
|
LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size,
|
||||||
|
|
@ -1100,11 +1101,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
|
||||||
/// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0
|
/// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0
|
||||||
#[deprecated = "use Window::request_ime_update instead"]
|
#[deprecated = "use Window::request_ime_update instead"]
|
||||||
fn set_ime_cursor_area(&self, position: Position, size: Size) {
|
fn set_ime_cursor_area(&self, position: Position, size: Size) {
|
||||||
if self
|
if self.ime_capabilities().map(|caps| caps.cursor_area()).unwrap_or(false) {
|
||||||
.ime_capabilities()
|
|
||||||
.map(|caps| caps.contains(ImeCapabilities::CURSOR_AREA))
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
let _ = self.request_ime_update(ImeRequest::Update(
|
let _ = self.request_ime_update(ImeRequest::Update(
|
||||||
ImeRequestData::default().with_cursor_area(position, size),
|
ImeRequestData::default().with_cursor_area(position, size),
|
||||||
));
|
));
|
||||||
|
|
@ -1138,7 +1135,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
|
||||||
let action = if allowed {
|
let action = if allowed {
|
||||||
let position = LogicalPosition::new(0, 0);
|
let position = LogicalPosition::new(0, 0);
|
||||||
let size = LogicalSize::new(0, 0);
|
let size = LogicalSize::new(0, 0);
|
||||||
let ime_caps = ImeCapabilities::CURSOR_AREA | ImeCapabilities::PURPOSE;
|
let ime_caps = ImeCapabilities::new().with_purpose().with_cursor_area();
|
||||||
let request_data = ImeRequestData {
|
let request_data = ImeRequestData {
|
||||||
purpose: Some(ImePurpose::Normal),
|
purpose: Some(ImePurpose::Normal),
|
||||||
// WARNING: there's nothing sensible to use here by default.
|
// WARNING: there's nothing sensible to use here by default.
|
||||||
|
|
@ -1162,11 +1159,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
|
||||||
/// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
|
/// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
|
||||||
#[deprecated = "use Window::request_ime_update instead"]
|
#[deprecated = "use Window::request_ime_update instead"]
|
||||||
fn set_ime_purpose(&self, purpose: ImePurpose) {
|
fn set_ime_purpose(&self, purpose: ImePurpose) {
|
||||||
if self
|
if self.ime_capabilities().map(|caps| caps.purpose()).unwrap_or(false) {
|
||||||
.ime_capabilities()
|
|
||||||
.map(|caps| caps.contains(ImeCapabilities::PURPOSE))
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
let _ = self.request_ime_update(ImeRequest::Update(ImeRequestData {
|
let _ = self.request_ime_update(ImeRequest::Update(ImeRequestData {
|
||||||
purpose: Some(purpose),
|
purpose: Some(purpose),
|
||||||
..ImeRequestData::default()
|
..ImeRequestData::default()
|
||||||
|
|
@ -1197,7 +1190,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
|
||||||
/// // Clear previous state by switching off IME
|
/// // Clear previous state by switching off IME
|
||||||
/// window.request_ime_update(ImeRequest::Disable).expect("Disable cannot fail");
|
/// window.request_ime_update(ImeRequest::Disable).expect("Disable cannot fail");
|
||||||
///
|
///
|
||||||
/// let ime_caps = ImeCapabilities::CURSOR_AREA | ImeCapabilities::PURPOSE;
|
/// let ime_caps = ImeCapabilities::new().with_cursor_area().with_purpose();
|
||||||
/// let request_data = ImeRequestData::default()
|
/// let request_data = ImeRequestData::default()
|
||||||
/// .with_purpose(ImePurpose::Normal)
|
/// .with_purpose(ImePurpose::Normal)
|
||||||
/// .with_cursor_area(cursor_pos, cursor_size);
|
/// .with_cursor_area(cursor_pos, cursor_size);
|
||||||
|
|
@ -1666,12 +1659,11 @@ impl ImeEnableRequest {
|
||||||
/// This will return [`None`] if some capability was requested but its initial value was not
|
/// This will return [`None`] if some capability was requested but its initial value was not
|
||||||
/// set by the user or value was set by the user, but capability not requested.
|
/// set by the user or value was set by the user, but capability not requested.
|
||||||
pub const fn new(capabilities: ImeCapabilities, request_data: ImeRequestData) -> Option<Self> {
|
pub const fn new(capabilities: ImeCapabilities, request_data: ImeRequestData) -> Option<Self> {
|
||||||
if capabilities.contains(ImeCapabilities::CURSOR_AREA) ^ request_data.cursor_area.is_some()
|
if capabilities.cursor_area() ^ request_data.cursor_area.is_some() {
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if capabilities.contains(ImeCapabilities::PURPOSE) ^ request_data.purpose.is_some() {
|
if capabilities.purpose() ^ request_data.purpose.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1694,22 +1686,58 @@ impl ImeEnableRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags! {
|
/// IME capabilities supported by client.
|
||||||
/// IME capabilities supported by client.
|
///
|
||||||
|
/// For example, if the client doesn't support [`ImeCapabilities::cursor_area()`], then not enabling
|
||||||
|
/// it will make IME hide the popup window instead of placing it arbitrary over the
|
||||||
|
/// client's window surface.
|
||||||
|
///
|
||||||
|
/// When the capability is not enabled or not supported by the IME, trying to update its'
|
||||||
|
/// corresponding data with [`ImeRequest`] will be ignored.
|
||||||
|
///
|
||||||
|
/// New capabilities may be added to this struct in the future.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||||
|
pub struct ImeCapabilities(ImeCapabilitiesFlags);
|
||||||
|
|
||||||
|
impl ImeCapabilities {
|
||||||
|
/// Returns a new empty set of capabilities.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks `purpose` as supported.
|
||||||
///
|
///
|
||||||
/// For example, if the client doesn't support [`ImeCapabilities::CURSOR_AREA`] not enabling
|
/// For more details see [`ImeRequestData::with_purpose`].
|
||||||
/// it will make IME hide the popup window instead of placing it arbitrary over the
|
pub const fn with_purpose(self) -> Self {
|
||||||
/// client's window surface.
|
Self(self.0.union(ImeCapabilitiesFlags::PURPOSE))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `purpose` is supported.
|
||||||
|
pub const fn purpose(&self) -> bool {
|
||||||
|
self.0.contains(ImeCapabilitiesFlags::PURPOSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks `cursor_area` as supported.
|
||||||
///
|
///
|
||||||
/// When the capability is not enabled or not supported by the IME, trying to update its'
|
/// For more details see [`ImeRequestData::with_cursor_area`].
|
||||||
/// corresponding data with [`ImeRequest`] will be ignored.
|
pub const fn with_cursor_area(self) -> Self {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
Self(self.0.union(ImeCapabilitiesFlags::CURSOR_AREA))
|
||||||
pub struct ImeCapabilities: u32 {
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `cursor_area` is supported.
|
||||||
|
pub const fn cursor_area(&self) -> bool {
|
||||||
|
self.0.contains(ImeCapabilitiesFlags::CURSOR_AREA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||||
|
pub(crate) struct ImeCapabilitiesFlags : u8 {
|
||||||
/// Client supports setting IME purpose.
|
/// Client supports setting IME purpose.
|
||||||
const PURPOSE = 0b1;
|
const PURPOSE = 1 << 0;
|
||||||
/// Client supports reporting cursor area for IME popup to
|
/// Client supports reporting cursor area for IME popup to
|
||||||
/// appear.
|
/// appear.
|
||||||
const CURSOR_AREA = 0b10;
|
const CURSOR_AREA = 1 << 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1856,20 +1884,25 @@ mod tests {
|
||||||
let position: Position = LogicalPosition::new(0, 0).into();
|
let position: Position = LogicalPosition::new(0, 0).into();
|
||||||
let size: Size = LogicalSize::new(0, 0).into();
|
let size: Size = LogicalSize::new(0, 0).into();
|
||||||
|
|
||||||
assert!(ImeEnableRequest::new(ImeCapabilities::CURSOR_AREA, ImeRequestData::default())
|
assert!(ImeEnableRequest::new(
|
||||||
.is_none());
|
ImeCapabilities::new().with_cursor_area(),
|
||||||
assert!(
|
ImeRequestData::default()
|
||||||
ImeEnableRequest::new(ImeCapabilities::PURPOSE, ImeRequestData::default()).is_none()
|
)
|
||||||
);
|
.is_none());
|
||||||
|
assert!(ImeEnableRequest::new(
|
||||||
|
ImeCapabilities::new().with_purpose(),
|
||||||
|
ImeRequestData::default()
|
||||||
|
)
|
||||||
|
.is_none());
|
||||||
|
|
||||||
assert!(ImeEnableRequest::new(
|
assert!(ImeEnableRequest::new(
|
||||||
ImeCapabilities::CURSOR_AREA,
|
ImeCapabilities::new().with_cursor_area(),
|
||||||
ImeRequestData::default().with_purpose(ImePurpose::Normal)
|
ImeRequestData::default().with_purpose(ImePurpose::Normal)
|
||||||
)
|
)
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
assert!(ImeEnableRequest::new(
|
assert!(ImeEnableRequest::new(
|
||||||
ImeCapabilities::empty(),
|
ImeCapabilities::new(),
|
||||||
ImeRequestData::default()
|
ImeRequestData::default()
|
||||||
.with_purpose(ImePurpose::Normal)
|
.with_purpose(ImePurpose::Normal)
|
||||||
.with_cursor_area(position, size)
|
.with_cursor_area(position, size)
|
||||||
|
|
@ -1877,7 +1910,7 @@ mod tests {
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
assert!(ImeEnableRequest::new(
|
assert!(ImeEnableRequest::new(
|
||||||
ImeCapabilities::CURSOR_AREA,
|
ImeCapabilities::new().with_cursor_area(),
|
||||||
ImeRequestData::default()
|
ImeRequestData::default()
|
||||||
.with_purpose(ImePurpose::Normal)
|
.with_purpose(ImePurpose::Normal)
|
||||||
.with_cursor_area(position, size)
|
.with_cursor_area(position, size)
|
||||||
|
|
@ -1885,13 +1918,13 @@ mod tests {
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
assert!(ImeEnableRequest::new(
|
assert!(ImeEnableRequest::new(
|
||||||
ImeCapabilities::CURSOR_AREA,
|
ImeCapabilities::new().with_cursor_area(),
|
||||||
ImeRequestData::default().with_cursor_area(position, size)
|
ImeRequestData::default().with_cursor_area(position, size)
|
||||||
)
|
)
|
||||||
.is_some());
|
.is_some());
|
||||||
|
|
||||||
assert!(ImeEnableRequest::new(
|
assert!(ImeEnableRequest::new(
|
||||||
ImeCapabilities::all(),
|
ImeCapabilities::new().with_purpose().with_cursor_area(),
|
||||||
ImeRequestData::default()
|
ImeRequestData::default()
|
||||||
.with_purpose(ImePurpose::Normal)
|
.with_purpose(ImePurpose::Normal)
|
||||||
.with_cursor_area(position, size)
|
.with_cursor_area(position, size)
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ impl ClientState {
|
||||||
/// Updates the fields of the state which are present in update_fields.
|
/// Updates the fields of the state which are present in update_fields.
|
||||||
pub fn update(&mut self, request_data: ImeRequestData, scale_factor: f64) {
|
pub fn update(&mut self, request_data: ImeRequestData, scale_factor: f64) {
|
||||||
if let Some(purpose) = request_data.purpose {
|
if let Some(purpose) = request_data.purpose {
|
||||||
if self.capabilities.contains(ImeCapabilities::PURPOSE) {
|
if self.capabilities.purpose() {
|
||||||
self.content_type = purpose.into();
|
self.content_type = purpose.into();
|
||||||
} else {
|
} else {
|
||||||
warn!("discarding ImePurpose update without capability enabled.");
|
warn!("discarding ImePurpose update without capability enabled.");
|
||||||
|
|
@ -269,7 +269,7 @@ impl ClientState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((position, size)) = request_data.cursor_area {
|
if let Some((position, size)) = request_data.cursor_area {
|
||||||
if self.capabilities.contains(ImeCapabilities::CURSOR_AREA) {
|
if self.capabilities.cursor_area() {
|
||||||
let position: LogicalPosition<u32> = position.to_logical(scale_factor);
|
let position: LogicalPosition<u32> = position.to_logical(scale_factor);
|
||||||
let size: LogicalSize<u32> = size.to_logical(scale_factor);
|
let size: LogicalSize<u32> = size.to_logical(scale_factor);
|
||||||
self.cursor_area = (position, size);
|
self.cursor_area = (position, size);
|
||||||
|
|
@ -280,11 +280,11 @@ impl ClientState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content_type(&self) -> Option<ContentType> {
|
pub fn content_type(&self) -> Option<ContentType> {
|
||||||
self.capabilities.contains(ImeCapabilities::PURPOSE).then_some(self.content_type)
|
self.capabilities.purpose().then_some(self.content_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_area(&self) -> Option<(LogicalPosition<u32>, LogicalSize<u32>)> {
|
pub fn cursor_area(&self) -> Option<(LogicalPosition<u32>, LogicalSize<u32>)> {
|
||||||
self.capabilities.contains(ImeCapabilities::CURSOR_AREA).then_some(self.cursor_area)
|
self.capabilities.cursor_area().then_some(self.cursor_area)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1051,7 +1051,7 @@ impl CoreWindow for Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((spot, size)) = request_data.cursor_area {
|
if let Some((spot, size)) = request_data.cursor_area {
|
||||||
if capabilities.contains(ImeCapabilities::CURSOR_AREA) {
|
if capabilities.cursor_area() {
|
||||||
let scale_factor = state.scale_factor;
|
let scale_factor = state.scale_factor;
|
||||||
ImeContext::current(window.hwnd()).set_ime_cursor_area(
|
ImeContext::current(window.hwnd()).set_ime_cursor_area(
|
||||||
spot,
|
spot,
|
||||||
|
|
|
||||||
|
|
@ -2112,7 +2112,7 @@ impl UnownedWindow {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((position, size)) = state.cursor_area {
|
if let Some((position, size)) = state.cursor_area {
|
||||||
if capabilities.contains(ImeCapabilities::CURSOR_AREA) {
|
if capabilities.cursor_area() {
|
||||||
self.set_ime_cursor_area(position, size);
|
self.set_ime_cursor_area(position, size);
|
||||||
} else {
|
} else {
|
||||||
warn!("discarding IME cursor area update without capability enabled.");
|
warn!("discarding IME cursor area update without capability enabled.");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue