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}
200