1 | use std::{collections::HashMap, mem, sync::Arc}; |
2 | |
3 | use super::{ffi, XConnection, XError}; |
4 | |
5 | use super::{ |
6 | context::ImeContext, |
7 | input_method::{InputMethod, PotentialInputMethods}, |
8 | }; |
9 | use crate::platform_impl::platform::x11::ime::ImeEventSender; |
10 | |
11 | pub(crate) unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> { |
12 | unsafe { (xconn.xlib.XCloseIM)(im) }; |
13 | xconn.check_errors() |
14 | } |
15 | |
16 | pub(crate) unsafe fn destroy_ic(xconn: &Arc<XConnection>, ic: ffi::XIC) -> Result<(), XError> { |
17 | unsafe { (xconn.xlib.XDestroyIC)(ic) }; |
18 | xconn.check_errors() |
19 | } |
20 | |
21 | pub(crate) struct ImeInner { |
22 | pub xconn: Arc<XConnection>, |
23 | pub im: Option<InputMethod>, |
24 | pub potential_input_methods: PotentialInputMethods, |
25 | pub contexts: HashMap<ffi::Window, Option<ImeContext>>, |
26 | // WARNING: this is initially zeroed! |
27 | pub destroy_callback: ffi::XIMCallback, |
28 | pub event_sender: ImeEventSender, |
29 | // Indicates whether or not the the input method was destroyed on the server end |
30 | // (i.e. if ibus/fcitx/etc. was terminated/restarted) |
31 | pub is_destroyed: bool, |
32 | pub is_fallback: bool, |
33 | } |
34 | |
35 | impl ImeInner { |
36 | pub(crate) fn new( |
37 | xconn: Arc<XConnection>, |
38 | potential_input_methods: PotentialInputMethods, |
39 | event_sender: ImeEventSender, |
40 | ) -> Self { |
41 | ImeInner { |
42 | xconn, |
43 | im: None, |
44 | potential_input_methods, |
45 | contexts: HashMap::new(), |
46 | destroy_callback: unsafe { mem::zeroed() }, |
47 | event_sender, |
48 | is_destroyed: false, |
49 | is_fallback: false, |
50 | } |
51 | } |
52 | |
53 | pub unsafe fn close_im_if_necessary(&self) -> Result<bool, XError> { |
54 | if !self.is_destroyed && self.im.is_some() { |
55 | unsafe { close_im(&self.xconn, self.im.as_ref().unwrap().im) }.map(|_| true) |
56 | } else { |
57 | Ok(false) |
58 | } |
59 | } |
60 | |
61 | pub unsafe fn destroy_ic_if_necessary(&self, ic: ffi::XIC) -> Result<bool, XError> { |
62 | if !self.is_destroyed { |
63 | unsafe { destroy_ic(&self.xconn, ic) }.map(|_| true) |
64 | } else { |
65 | Ok(false) |
66 | } |
67 | } |
68 | |
69 | pub unsafe fn destroy_all_contexts_if_necessary(&self) -> Result<bool, XError> { |
70 | for context in self.contexts.values().flatten() { |
71 | unsafe { self.destroy_ic_if_necessary(context.ic)? }; |
72 | } |
73 | Ok(!self.is_destroyed) |
74 | } |
75 | } |
76 | |