winit/platform_impl/linux/x11/ime/
mod.rs
1mod callbacks;
4mod context;
5mod inner;
6mod input_method;
7
8use std::sync::mpsc::{Receiver, Sender};
9use std::sync::Arc;
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13use tracing::debug;
14
15use self::callbacks::*;
16use self::context::ImeContext;
17pub use self::context::ImeContextCreationError;
18use self::inner::{close_im, ImeInner};
19use self::input_method::{PotentialInputMethods, Style};
20use super::{ffi, util, XConnection, XError};
21
22#[derive(Debug, Clone, PartialEq, Eq, Hash)]
23#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
24pub enum ImeEvent {
25 Enabled,
26 Start,
27 Update(String, usize),
28 End,
29 Disabled,
30}
31
32pub type ImeReceiver = Receiver<ImeRequest>;
33pub type ImeSender = Sender<ImeRequest>;
34pub type ImeEventReceiver = Receiver<(ffi::Window, ImeEvent)>;
35pub type ImeEventSender = Sender<(ffi::Window, ImeEvent)>;
36
37pub enum ImeRequest {
39 Position(ffi::Window, i16, i16),
41
42 Allow(ffi::Window, bool),
44}
45
46#[derive(Debug)]
47pub(crate) enum ImeCreationError {
48 OpenFailure(Box<PotentialInputMethods>),
50 SetDestroyCallbackFailed(#[allow(dead_code)] XError),
51}
52
53pub(crate) struct Ime {
54 xconn: Arc<XConnection>,
55 inner: Box<ImeInner>,
58}
59
60impl Ime {
61 pub fn new(
62 xconn: Arc<XConnection>,
63 event_sender: ImeEventSender,
64 ) -> Result<Self, ImeCreationError> {
65 let potential_input_methods = PotentialInputMethods::new(&xconn);
66
67 let (mut inner, client_data) = {
68 let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods, event_sender));
69 let inner_ptr = Box::into_raw(inner);
70 let client_data = inner_ptr as _;
71 let destroy_callback =
72 ffi::XIMCallback { client_data, callback: Some(xim_destroy_callback) };
73 inner = unsafe { Box::from_raw(inner_ptr) };
74 inner.destroy_callback = destroy_callback;
75 (inner, client_data)
76 };
77
78 let xconn = Arc::clone(&inner.xconn);
79
80 let input_method = inner.potential_input_methods.open_im(
81 &xconn,
82 Some(&|| {
83 let _ = unsafe { set_instantiate_callback(&xconn, client_data) };
84 }),
85 );
86
87 let is_fallback = input_method.is_fallback();
88 if let Some(input_method) = input_method.ok() {
89 inner.is_fallback = is_fallback;
90 unsafe {
91 let result = set_destroy_callback(&xconn, input_method.im, &inner)
92 .map_err(ImeCreationError::SetDestroyCallbackFailed);
93 if result.is_err() {
94 let _ = close_im(&xconn, input_method.im);
95 }
96 result?;
97 }
98 inner.im = Some(input_method);
99 Ok(Ime { xconn, inner })
100 } else {
101 Err(ImeCreationError::OpenFailure(Box::new(inner.potential_input_methods)))
102 }
103 }
104
105 pub fn is_destroyed(&self) -> bool {
106 self.inner.is_destroyed
107 }
108
109 pub fn create_context(
114 &mut self,
115 window: ffi::Window,
116 with_preedit: bool,
117 ) -> Result<bool, ImeContextCreationError> {
118 let context = if self.is_destroyed() {
119 None
121 } else {
122 let im = self.inner.im.as_ref().unwrap();
123 let style = if with_preedit { im.preedit_style } else { im.none_style };
124
125 let context = unsafe {
126 ImeContext::new(
127 &self.inner.xconn,
128 im.im,
129 style,
130 window,
131 None,
132 self.inner.event_sender.clone(),
133 )?
134 };
135
136 let event = if matches!(style, Style::None(_)) {
138 if with_preedit {
139 debug!("failed to create IME context with preedit support.")
140 }
141 ImeEvent::Disabled
142 } else {
143 if !with_preedit {
144 debug!("failed to create IME context without preedit support.")
145 }
146 ImeEvent::Enabled
147 };
148
149 self.inner.event_sender.send((window, event)).expect("Failed to send enabled event");
150
151 Some(context)
152 };
153
154 self.inner.contexts.insert(window, context);
155 Ok(!self.is_destroyed())
156 }
157
158 pub fn get_context(&self, window: ffi::Window) -> Option<ffi::XIC> {
159 if self.is_destroyed() {
160 return None;
161 }
162 if let Some(Some(context)) = self.inner.contexts.get(&window) {
163 Some(context.ic)
164 } else {
165 None
166 }
167 }
168
169 pub fn remove_context(&mut self, window: ffi::Window) -> Result<bool, XError> {
170 if let Some(Some(context)) = self.inner.contexts.remove(&window) {
171 unsafe {
172 self.inner.destroy_ic_if_necessary(context.ic)?;
173 }
174 Ok(true)
175 } else {
176 Ok(false)
177 }
178 }
179
180 pub fn focus(&mut self, window: ffi::Window) -> Result<bool, XError> {
181 if self.is_destroyed() {
182 return Ok(false);
183 }
184 if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
185 context.focus(&self.xconn).map(|_| true)
186 } else {
187 Ok(false)
188 }
189 }
190
191 pub fn unfocus(&mut self, window: ffi::Window) -> Result<bool, XError> {
192 if self.is_destroyed() {
193 return Ok(false);
194 }
195 if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
196 context.unfocus(&self.xconn).map(|_| true)
197 } else {
198 Ok(false)
199 }
200 }
201
202 pub fn send_xim_spot(&mut self, window: ffi::Window, x: i16, y: i16) {
203 if self.is_destroyed() {
204 return;
205 }
206 if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
207 context.set_spot(&self.xconn, x as _, y as _);
208 }
209 }
210
211 pub fn set_ime_allowed(&mut self, window: ffi::Window, allowed: bool) {
212 if self.is_destroyed() {
213 return;
214 }
215
216 if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
217 if allowed == context.is_allowed() {
218 return;
219 }
220 }
221
222 let _ = self.remove_context(window);
224
225 let _ = self.create_context(window, allowed);
227 }
228}
229
230impl Drop for Ime {
231 fn drop(&mut self) {
232 unsafe {
233 let _ = self.inner.destroy_all_contexts_if_necessary();
234 let _ = self.inner.close_im_if_necessary();
235 }
236 }
237}