1 | use super::{Context, Keysym}; |
2 | use crate::xkb::ffi::compose::*; |
3 | use std::borrow::Cow; |
4 | use std::ffi::CStr; |
5 | use std::ffi::CString; |
6 | use std::ffi::OsStr; |
7 | use std::mem; |
8 | use std::str; |
9 | |
10 | pub type CompileFlags = u32; |
11 | pub const COMPILE_NO_FLAGS: CompileFlags = 0; |
12 | |
13 | pub type Format = u32; |
14 | pub const FORMAT_TEXT_V1: Format = 1; |
15 | |
16 | pub type StateFlags = u32; |
17 | pub const STATE_NO_FLAGS: StateFlags = 0; |
18 | |
19 | #[derive (Eq, PartialEq, Copy, Clone, Debug)] |
20 | #[repr (C)] |
21 | pub enum Status { |
22 | Nothing = 0, |
23 | Composing = 1, |
24 | Composed, |
25 | Cancelled, |
26 | } |
27 | |
28 | #[derive (Eq, PartialEq, Copy, Clone, Debug)] |
29 | #[repr (C)] |
30 | pub enum FeedResult { |
31 | Ignored, |
32 | Accepted, |
33 | } |
34 | |
35 | pub struct Table { |
36 | ptr: *mut xkb_compose_table, |
37 | } |
38 | |
39 | impl 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 | |
101 | impl Drop for Table { |
102 | fn drop(&mut self) { |
103 | unsafe { |
104 | xkb_compose_table_unref(self.ptr); |
105 | } |
106 | } |
107 | } |
108 | |
109 | impl Clone for Table { |
110 | fn clone(&self) -> Table { |
111 | Table { |
112 | ptr: unsafe { xkb_compose_table_ref(self.ptr) }, |
113 | } |
114 | } |
115 | } |
116 | |
117 | pub struct State { |
118 | ptr: *mut xkb_compose_state, |
119 | } |
120 | |
121 | impl 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 | |
185 | impl Drop for State { |
186 | fn drop(&mut self) { |
187 | unsafe { |
188 | xkb_compose_state_unref(self.ptr); |
189 | } |
190 | } |
191 | } |
192 | |
193 | impl Clone for State { |
194 | fn clone(&self) -> State { |
195 | State { |
196 | ptr: unsafe { xkb_compose_state_ref(self.ptr) }, |
197 | } |
198 | } |
199 | } |
200 | |