xkbcommon/xkb/
compose.rs

1use super::{Context, Keysym};
2use crate::xkb::ffi::compose::*;
3use std::borrow::Cow;
4use std::ffi::CStr;
5use std::ffi::CString;
6use std::ffi::OsStr;
7use std::mem;
8use std::str;
9
10pub type CompileFlags = u32;
11pub const COMPILE_NO_FLAGS: CompileFlags = 0;
12
13pub type Format = u32;
14pub const FORMAT_TEXT_V1: Format = 1;
15
16pub type StateFlags = u32;
17pub const STATE_NO_FLAGS: StateFlags = 0;
18
19#[derive(Eq, PartialEq, Copy, Clone, Debug)]
20#[repr(C)]
21pub enum Status {
22    Nothing = 0,
23    Composing = 1,
24    Composed,
25    Cancelled,
26}
27
28#[derive(Eq, PartialEq, Copy, Clone, Debug)]
29#[repr(C)]
30pub enum FeedResult {
31    Ignored,
32    Accepted,
33}
34
35pub struct Table {
36    ptr: *mut xkb_compose_table,
37}
38
39impl Table {
40    /// Build a table from a locale.
41    /// The locale is typically obtained from environment variables.
42    ///
43    /// # Panics
44    /// May panic if the locale contain inner null characters.
45    #[allow(clippy::result_unit_err, clippy::missing_errors_doc)]
46    pub fn new_from_locale(
47        context: &Context,
48        locale: &OsStr,
49        flags: CompileFlags,
50    ) -> Result<Table, ()> {
51        use std::os::unix::ffi::OsStrExt;
52
53        let locale_cstr = CStr::from_bytes_with_nul(locale.as_bytes());
54        let locale_cstr = match locale_cstr {
55            Ok(loc) => Cow::from(loc),
56            Err(_) => Cow::from(CString::new(locale.as_bytes().to_vec()).unwrap()),
57        };
58
59        let ptr = unsafe {
60            xkb_compose_table_new_from_locale(context.get_raw_ptr(), locale_cstr.as_ptr(), flags)
61        };
62        if ptr.is_null() {
63            Err(())
64        } else {
65            Ok(Table { ptr })
66        }
67    }
68
69    #[allow(
70        clippy::result_unit_err,
71        clippy::missing_panics_doc,
72        clippy::missing_errors_doc
73    )]
74    pub fn new_from_buffer<T: AsRef<[u8]>>(
75        context: &Context,
76        buffer: T,
77        locale: &str,
78        format: Format,
79        flags: CompileFlags,
80    ) -> Result<Table, ()> {
81        let buffer = buffer.as_ref();
82        let locale = CString::new(locale).unwrap();
83        let ptr = unsafe {
84            xkb_compose_table_new_from_buffer(
85                context.get_raw_ptr(),
86                buffer.as_ptr().cast(),
87                buffer.len() as _,
88                locale.as_ptr(),
89                format,
90                flags,
91            )
92        };
93        if ptr.is_null() {
94            Err(())
95        } else {
96            Ok(Table { ptr })
97        }
98    }
99}
100
101impl Drop for Table {
102    fn drop(&mut self) {
103        unsafe {
104            xkb_compose_table_unref(self.ptr);
105        }
106    }
107}
108
109impl Clone for Table {
110    fn clone(&self) -> Table {
111        Table {
112            ptr: unsafe { xkb_compose_table_ref(self.ptr) },
113        }
114    }
115}
116
117pub struct State {
118    ptr: *mut xkb_compose_state,
119}
120
121impl State {
122    /// # Safety
123    /// `ptr` must be a valid pointer to `xkb_compose_state`
124    #[must_use]
125    pub unsafe fn from_raw_ptr(ptr: *mut xkb_compose_state) -> State {
126        State { ptr }
127    }
128
129    pub fn get_raw_ptr(&self) -> *mut xkb_compose_state {
130        self.ptr
131    }
132
133    #[must_use]
134    pub fn new(table: &Table, flags: StateFlags) -> State {
135        State {
136            ptr: unsafe { xkb_compose_state_new(table.ptr, flags) },
137        }
138    }
139
140    #[must_use]
141    pub fn compose_table(&self) -> Table {
142        Table {
143            ptr: unsafe { xkb_compose_table_ref(xkb_compose_state_get_compose_table(self.ptr)) },
144        }
145    }
146
147    pub fn feed(&mut self, keysym: Keysym) -> FeedResult {
148        unsafe { mem::transmute(xkb_compose_state_feed(self.ptr, keysym.raw())) }
149    }
150
151    pub fn reset(&mut self) {
152        unsafe {
153            xkb_compose_state_reset(self.ptr);
154        }
155    }
156
157    #[must_use]
158    pub fn status(&self) -> Status {
159        unsafe { mem::transmute(xkb_compose_state_get_status(self.ptr)) }
160    }
161
162    #[must_use]
163    pub fn utf8(&self) -> Option<String> {
164        let mut buffer = [0_u8; 256];
165
166        unsafe {
167            match xkb_compose_state_get_utf8(self.ptr, buffer.as_mut_ptr().cast(), buffer.len()) {
168                0 => None,
169                n => Some(str::from_utf8_unchecked(&buffer[..n as usize]).into()),
170            }
171        }
172    }
173
174    #[must_use]
175    pub fn keysym(&self) -> Option<Keysym> {
176        unsafe {
177            match Keysym::new(xkb_compose_state_get_one_sym(self.ptr)) {
178                xkeysym::NO_SYMBOL => None,
179                value => Some(value),
180            }
181        }
182    }
183}
184
185impl Drop for State {
186    fn drop(&mut self) {
187        unsafe {
188            xkb_compose_state_unref(self.ptr);
189        }
190    }
191}
192
193impl Clone for State {
194    fn clone(&self) -> State {
195        State {
196            ptr: unsafe { xkb_compose_state_ref(self.ptr) },
197        }
198    }
199}