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