| 1 | use std::collections::HashMap; |
| 2 | use std::mem; |
| 3 | use std::sync::Arc; |
| 4 | |
| 5 | use super::{ffi, XConnection, XError}; |
| 6 | |
| 7 | use super::context::ImeContext; |
| 8 | use super::input_method::{InputMethod, PotentialInputMethods}; |
| 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 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 | |