1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
mod callbacks;
mod context;
mod inner;
mod input_method;
use std::sync::{
mpsc::{Receiver, Sender},
Arc,
};
use super::{ffi, util, XConnection, XError};
pub use self::context::ImeContextCreationError;
use self::{
callbacks::*,
context::ImeContext,
inner::{close_im, ImeInner},
input_method::PotentialInputMethods,
};
pub type ImeReceiver = Receiver<(ffi::Window, i16, i16)>;
pub type ImeSender = Sender<(ffi::Window, i16, i16)>;
#[derive(Debug)]
pub enum ImeCreationError {
OpenFailure(PotentialInputMethods),
SetDestroyCallbackFailed(XError),
}
pub struct Ime {
xconn: Arc<XConnection>,
inner: Box<ImeInner>,
}
impl Ime {
pub fn new(xconn: Arc<XConnection>) -> Result<Self, ImeCreationError> {
let potential_input_methods = PotentialInputMethods::new(&xconn);
let (mut inner, client_data) = {
let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods));
let inner_ptr = Box::into_raw(inner);
let client_data = inner_ptr as _;
let destroy_callback = ffi::XIMCallback {
client_data,
callback: Some(xim_destroy_callback),
};
inner = unsafe { Box::from_raw(inner_ptr) };
inner.destroy_callback = destroy_callback;
(inner, client_data)
};
let xconn = Arc::clone(&inner.xconn);
let input_method = inner.potential_input_methods.open_im(
&xconn,
Some(&|| {
let _ = unsafe { set_instantiate_callback(&xconn, client_data) };
}),
);
let is_fallback = input_method.is_fallback();
if let Some(input_method) = input_method.ok() {
inner.im = input_method.im;
inner.is_fallback = is_fallback;
unsafe {
let result = set_destroy_callback(&xconn, input_method.im, &*inner)
.map_err(ImeCreationError::SetDestroyCallbackFailed);
if result.is_err() {
let _ = close_im(&xconn, input_method.im);
}
result?;
}
Ok(Ime { xconn, inner })
} else {
Err(ImeCreationError::OpenFailure(inner.potential_input_methods))
}
}
pub fn is_destroyed(&self) -> bool {
self.inner.is_destroyed
}
pub fn create_context(&mut self, window: ffi::Window) -> Result<bool, ImeContextCreationError> {
let context = if self.is_destroyed() {
None
} else {
Some(unsafe { ImeContext::new(&self.inner.xconn, self.inner.im, window, None) }?)
};
self.inner.contexts.insert(window, context);
Ok(!self.is_destroyed())
}
pub fn get_context(&self, window: ffi::Window) -> Option<ffi::XIC> {
if self.is_destroyed() {
return None;
}
if let Some(&Some(ref context)) = self.inner.contexts.get(&window) {
Some(context.ic)
} else {
None
}
}
pub fn remove_context(&mut self, window: ffi::Window) -> Result<bool, XError> {
if let Some(Some(context)) = self.inner.contexts.remove(&window) {
unsafe {
self.inner.destroy_ic_if_necessary(context.ic)?;
}
Ok(true)
} else {
Ok(false)
}
}
pub fn focus(&mut self, window: ffi::Window) -> Result<bool, XError> {
if self.is_destroyed() {
return Ok(false);
}
if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
context.focus(&self.xconn).map(|_| true)
} else {
Ok(false)
}
}
pub fn unfocus(&mut self, window: ffi::Window) -> Result<bool, XError> {
if self.is_destroyed() {
return Ok(false);
}
if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
context.unfocus(&self.xconn).map(|_| true)
} else {
Ok(false)
}
}
pub fn send_xim_spot(&mut self, window: ffi::Window, x: i16, y: i16) {
if self.is_destroyed() {
return;
}
if let Some(&mut Some(ref mut context)) = self.inner.contexts.get_mut(&window) {
context.set_spot(&self.xconn, x as _, y as _);
}
}
}
impl Drop for Ime {
fn drop(&mut self) {
unsafe {
let _ = self.inner.destroy_all_contexts_if_necessary();
let _ = self.inner.close_im_if_necessary();
}
}
}