zed_xim/
server.rs

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    /// return `false` when event back to client
105    /// if return `true` it consumed and don't back to client
106    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}