1mod connection;
2
3use alloc::string::String;
4use alloc::vec;
5use alloc::vec::Vec;
6use core::fmt;
7use core::num::NonZeroU16;
8
9use xim_parser::{
10 CommitData, ErrorCode, ErrorFlag, Feedback, InputStyle, PreeditDrawStatus, Request,
11};
12
13pub use self::connection::{
14 InputContext, InputMethod, UserInputContext, XimConnection, XimConnections,
15};
16
17#[derive(Debug)]
18#[non_exhaustive]
19pub enum ServerError {
20 ClientNotExists,
21 ReadProtocol(xim_parser::ReadError),
22 XimError(xim_parser::ErrorCode, String),
23 InvalidReply,
24 Internal(String),
25 #[cfg(feature = "std")]
26 Other(alloc::boxed::Box<dyn std::error::Error + Send + Sync>),
27}
28
29impl From<xim_parser::ReadError> for ServerError {
30 fn from(e: xim_parser::ReadError) -> Self {
31 ServerError::ReadProtocol(e)
32 }
33}
34
35impl fmt::Display for ServerError {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 ServerError::ClientNotExists => write!(f, "Client doesn't exists"),
39 ServerError::ReadProtocol(e) => write!(f, "Can't read xim message: {}", e),
40 ServerError::XimError(e, d) => {
41 write!(f, "Client send error code: {:?}, detail: {}", e, d)
42 }
43 ServerError::InvalidReply => write!(f, "Invalid reply from client"),
44 ServerError::Internal(e) => write!(f, "Internal error: {}", e),
45 #[cfg(feature = "std")]
46 ServerError::Other(e) => write!(f, "Other error: {}", e),
47 }
48 }
49}
50
51#[cfg(feature = "std")]
52impl std::error::Error for ServerError {}
53
54pub trait ServerHandler<S: Server> {
55 type InputStyleArray: AsRef<[InputStyle]>;
56 type InputContextData;
57
58 fn new_ic_data(
59 &mut self,
60 server: &mut S,
61 input_style: InputStyle,
62 ) -> Result<Self::InputContextData, ServerError>;
63
64 fn input_styles(&self) -> Self::InputStyleArray;
65 fn filter_events(&self) -> u32;
66
67 fn handle_connect(&mut self, server: &mut S) -> Result<(), ServerError>;
68
69 fn handle_create_ic(
70 &mut self,
71 server: &mut S,
72 user_ic: &mut UserInputContext<Self::InputContextData>,
73 ) -> Result<(), ServerError>;
74
75 fn handle_destroy_ic(
76 &mut self,
77 server: &mut S,
78 user_ic: UserInputContext<Self::InputContextData>,
79 ) -> Result<(), ServerError>;
80 fn handle_reset_ic(
81 &mut self,
82 server: &mut S,
83 user_ic: &mut UserInputContext<Self::InputContextData>,
84 ) -> Result<String, ServerError>;
85
86 fn handle_set_focus(
87 &mut self,
88 server: &mut S,
89 user_ic: &mut UserInputContext<Self::InputContextData>,
90 ) -> Result<(), ServerError>;
91
92 fn handle_unset_focus(
93 &mut self,
94 server: &mut S,
95 user_ic: &mut UserInputContext<Self::InputContextData>,
96 ) -> Result<(), ServerError>;
97
98 fn handle_set_ic_values(
99 &mut self,
100 server: &mut S,
101 user_ic: &mut UserInputContext<Self::InputContextData>,
102 ) -> Result<(), ServerError>;
103
104 fn handle_forward_event(
107 &mut self,
108 server: &mut S,
109 user_ic: &mut UserInputContext<Self::InputContextData>,
110 xev: &S::XEvent,
111 ) -> Result<bool, ServerError>;
112}
113
114pub trait Server {
115 type XEvent;
116
117 fn error(
118 &mut self,
119 client_win: u32,
120 code: ErrorCode,
121 detail: String,
122 input_method_id: Option<NonZeroU16>,
123 user_ic_id: Option<NonZeroU16>,
124 ) -> Result<(), ServerError>;
125
126 fn preedit_draw(&mut self, ic: &mut InputContext, s: &str) -> Result<(), ServerError>;
127 fn commit(&mut self, ic: &InputContext, s: &str) -> Result<(), ServerError>;
128
129 fn set_event_mask(
130 &mut self,
131 ic: &InputContext,
132 forward_event_mask: u32,
133 synchronous_event_mask: u32,
134 ) -> Result<(), ServerError>;
135}
136
137impl<S: ServerCore> Server for S {
138 type XEvent = S::XEvent;
139
140 fn error(
141 &mut self,
142 client_win: u32,
143 code: ErrorCode,
144 detail: String,
145 input_method_id: Option<NonZeroU16>,
146 user_ic_id: Option<NonZeroU16>,
147 ) -> Result<(), ServerError> {
148 let mut flag = ErrorFlag::empty();
149
150 let input_method_id = if let Some(id) = input_method_id {
151 flag |= ErrorFlag::INPUT_METHOD_ID_VALID;
152 id.get()
153 } else {
154 0
155 };
156
157 let input_context_id = if let Some(id) = user_ic_id {
158 flag |= ErrorFlag::INPUT_CONTEXT_ID_VALID;
159 id.get()
160 } else {
161 0
162 };
163
164 self.send_req(
165 client_win,
166 Request::Error {
167 input_method_id,
168 input_context_id,
169 code,
170 detail,
171 flag,
172 },
173 )
174 }
175
176 fn preedit_draw(&mut self, ic: &mut InputContext, s: &str) -> Result<(), ServerError> {
177 let preedit_length = s.chars().count();
178
179 if preedit_length == 0 {
180 if ic.preedit_started {
181 self.send_req(
182 ic.client_win(),
183 Request::PreeditDraw {
184 input_method_id: ic.input_method_id().get(),
185 input_context_id: ic.input_context_id().get(),
186 chg_first: 0,
187 chg_length: ic.prev_preedit_length as _,
188 caret: preedit_length as _,
189 preedit_string: Vec::new(),
190 feedbacks: Vec::new(),
191 status: PreeditDrawStatus::NO_FEEDBACK | PreeditDrawStatus::NO_STRING,
192 },
193 )?;
194 self.send_req(
195 ic.client_win(),
196 Request::PreeditDone {
197 input_method_id: ic.input_method_id().get(),
198 input_context_id: ic.input_context_id().get(),
199 },
200 )?;
201 ic.preedit_started = false;
202 ic.prev_preedit_length = 0;
203 }
204 } else {
205 if !ic.preedit_started {
206 self.send_req(
207 ic.client_win(),
208 Request::PreeditStart {
209 input_method_id: ic.input_method_id().get(),
210 input_context_id: ic.input_context_id().get(),
211 },
212 )?;
213 ic.preedit_started = true;
214 }
215
216 self.send_req(
217 ic.client_win(),
218 Request::PreeditDraw {
219 input_method_id: ic.input_method_id().get(),
220 input_context_id: ic.input_context_id().get(),
221 chg_first: 0,
222 chg_length: ic.prev_preedit_length as _,
223 caret: preedit_length as _,
224 preedit_string: xim_ctext::utf8_to_compound_text(s),
225 feedbacks: vec![Feedback::Underline; preedit_length],
226 status: PreeditDrawStatus::empty(),
227 },
228 )?;
229
230 ic.prev_preedit_length = preedit_length;
231 }
232
233 Ok(())
234 }
235
236 fn commit(&mut self, ic: &InputContext, s: &str) -> Result<(), ServerError> {
237 self.send_req(
238 ic.client_win(),
239 Request::Commit {
240 input_method_id: ic.input_method_id().get(),
241 input_context_id: ic.input_context_id().get(),
242 data: CommitData::Chars {
243 commited: xim_ctext::utf8_to_compound_text(s),
244 syncronous: false,
245 },
246 },
247 )
248 }
249
250 fn set_event_mask(
251 &mut self,
252 ic: &InputContext,
253 forward_event_mask: u32,
254 synchronous_event_mask: u32,
255 ) -> Result<(), ServerError> {
256 self.send_req(
257 ic.client_win(),
258 Request::SetEventMask {
259 input_method_id: ic.input_method_id().get(),
260 input_context_id: ic.input_context_id().get(),
261 forward_event_mask,
262 synchronous_event_mask,
263 },
264 )
265 }
266}
267
268pub trait ServerCore {
269 type XEvent;
270
271 fn deserialize_event(&self, ev: &xim_parser::XEvent) -> Self::XEvent;
272 fn send_req(&mut self, client_win: u32, req: Request) -> Result<(), ServerError>;
273}