1use std::ffi::CStr;
7
8use glib::translate::*;
9
10use crate::{Editable, ffi, prelude::*, subclass::prelude::*};
11
12pub trait EditableImpl: ObjectImpl + ObjectSubclass<Type: IsA<Editable>> {
13 fn insert_text(&self, new_text: &str, position: &mut i32) {
14 self.parent_insert_text(new_text, position);
15 }
16
17 fn delete_text(&self, start_pos: i32, end_pos: i32) {
18 self.parent_delete_text(start_pos, end_pos);
19 }
20
21 fn changed(&self) {
22 self.parent_changed();
23 }
24
25 fn do_insert_text(&self, new_text: &str, position: &mut i32) {
26 self.parent_do_insert_text(new_text, position);
27 }
28
29 fn do_delete_text(&self, start_pos: i32, end_pos: i32) {
30 self.parent_do_delete_text(start_pos, end_pos);
31 }
32
33 #[doc(alias = "get_chars")]
34 fn chars(&self, start_pos: i32, end_pos: i32) -> Option<glib::GString> {
35 self.parent_chars(start_pos, end_pos)
36 }
37
38 fn set_selection_bounds(&self, start_pos: i32, end_pos: i32) {
39 self.parent_set_selection_bounds(start_pos, end_pos);
40 }
41
42 #[doc(alias = "get_selection_bounds")]
43 fn selection_bounds(&self) -> Option<(i32, i32)> {
44 self.parent_selection_bounds()
45 }
46
47 fn set_position(&self, position: i32) {
48 self.parent_set_position(position);
49 }
50
51 #[doc(alias = "get_position")]
52 fn position(&self) -> i32 {
53 self.parent_position()
54 }
55}
56
57pub trait EditableImplExt: EditableImpl {
58 fn parent_insert_text(&self, new_text: &str, position: &mut i32) {
59 unsafe {
60 let type_data = Self::type_data();
61 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
62 as *const ffi::GtkEditableInterface;
63
64 if let Some(func) = (*parent_iface).insert_text {
65 func(
66 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
67 new_text.as_ptr() as *const _,
68 new_text.len() as i32,
69 position,
70 );
71 }
72 }
73 }
74
75 fn parent_delete_text(&self, start_pos: i32, end_pos: i32) {
76 unsafe {
77 let type_data = Self::type_data();
78 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
79 as *const ffi::GtkEditableInterface;
80
81 if let Some(func) = (*parent_iface).delete_text {
82 func(
83 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
84 start_pos,
85 end_pos,
86 );
87 }
88 }
89 }
90
91 fn parent_changed(&self) {
92 unsafe {
93 let type_data = Self::type_data();
94 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
95 as *const ffi::GtkEditableInterface;
96
97 if let Some(func) = (*parent_iface).changed {
98 func(self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0);
99 }
100 }
101 }
102
103 fn parent_do_insert_text(&self, new_text: &str, position: &mut i32) {
104 unsafe {
105 let type_data = Self::type_data();
106 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
107 as *const ffi::GtkEditableInterface;
108
109 let func = (*parent_iface)
110 .do_insert_text
111 .expect("no parent \"do_insert_text\" implementation");
112 func(
113 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
114 new_text.as_ptr() as *const _,
115 new_text.len() as i32,
116 position,
117 );
118 }
119 }
120
121 fn parent_do_delete_text(&self, start_pos: i32, end_pos: i32) {
122 unsafe {
123 let type_data = Self::type_data();
124 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
125 as *const ffi::GtkEditableInterface;
126
127 let func = (*parent_iface)
128 .do_delete_text
129 .expect("no parent \"do_delete_text\" implementation");
130 func(
131 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
132 start_pos,
133 end_pos,
134 );
135 }
136 }
137
138 fn parent_chars(&self, start_pos: i32, end_pos: i32) -> Option<glib::GString> {
139 unsafe {
140 let type_data = Self::type_data();
141 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
142 as *const ffi::GtkEditableInterface;
143
144 let func = (*parent_iface)
145 .get_chars
146 .expect("no parent \"get_chars\" implementation");
147 from_glib_full(func(
148 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
149 start_pos,
150 end_pos,
151 ))
152 }
153 }
154
155 fn parent_set_selection_bounds(&self, start_pos: i32, end_pos: i32) {
156 unsafe {
157 let type_data = Self::type_data();
158 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
159 as *const ffi::GtkEditableInterface;
160
161 let func = (*parent_iface)
162 .set_selection_bounds
163 .expect("no parent \"set_selection_bounds\" implementation");
164 func(
165 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
166 start_pos,
167 end_pos,
168 );
169 }
170 }
171
172 fn parent_selection_bounds(&self) -> Option<(i32, i32)> {
173 unsafe {
174 let type_data = Self::type_data();
175 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
176 as *const ffi::GtkEditableInterface;
177
178 let func = (*parent_iface)
179 .get_selection_bounds
180 .expect("no parent \"get_selection_bounds\" implementation");
181 let mut start_pos = 0;
182 let mut end_pos = 0;
183 from_glib::<_, bool>(func(
184 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
185 &mut start_pos,
186 &mut end_pos,
187 ))
188 .then_some((start_pos, end_pos))
189 }
190 }
191
192 fn parent_set_position(&self, position: i32) {
193 unsafe {
194 let type_data = Self::type_data();
195 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
196 as *const ffi::GtkEditableInterface;
197
198 let func = (*parent_iface)
199 .set_position
200 .expect("no parent \"set_position\" implementation");
201 func(
202 self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0,
203 position,
204 );
205 }
206 }
207
208 fn parent_position(&self) -> i32 {
209 unsafe {
210 let type_data = Self::type_data();
211 let parent_iface = type_data.as_ref().parent_interface::<Editable>()
212 as *const ffi::GtkEditableInterface;
213
214 let func = (*parent_iface)
215 .get_position
216 .expect("no parent \"get_position\" implementation");
217 func(self.obj().unsafe_cast_ref::<Editable>().to_glib_none().0)
218 }
219 }
220}
221
222impl<T: EditableImpl> EditableImplExt for T {}
223
224unsafe impl<T: EditableImpl> IsImplementable<T> for Editable {
225 fn interface_init(iface: &mut glib::Interface<Self>) {
226 let iface = iface.as_mut();
227
228 if !crate::rt::is_initialized() {
229 panic!("GTK has to be initialized first");
230 }
231
232 iface.insert_text = Some(editable_insert_text::<T>);
233 iface.delete_text = Some(editable_delete_text::<T>);
234 iface.changed = Some(editable_changed::<T>);
235 iface.do_insert_text = Some(editable_do_insert_text::<T>);
236 iface.do_delete_text = Some(editable_do_delete_text::<T>);
237 iface.get_chars = Some(editable_get_chars::<T>);
238 iface.set_selection_bounds = Some(editable_set_selection_bounds::<T>);
239 iface.get_selection_bounds = Some(editable_get_selection_bounds::<T>);
240 iface.set_position = Some(editable_set_position::<T>);
241 iface.get_position = Some(editable_get_position::<T>);
242 }
243}
244
245unsafe extern "C" fn editable_insert_text<T: EditableImpl>(
246 editableptr: *mut ffi::GtkEditable,
247 new_text_ptr: *const glib::ffi::gchar,
248 new_text_length: i32,
249 position_ptr: *mut i32,
250) {
251 assert!(!editableptr.is_null());
252 assert!(!new_text_ptr.is_null());
253 assert!(!position_ptr.is_null());
254
255 let instance = unsafe { &*(editableptr as *mut T::Instance) };
256 let imp = instance.imp();
257
258 let new_text = if new_text_length < 0 {
259 unsafe { CStr::from_ptr(new_text_ptr).to_str().unwrap() }
260 } else {
261 let s = unsafe {
262 std::slice::from_raw_parts(new_text_ptr as *const _, new_text_length as usize)
263 };
264 str::from_utf8(s).unwrap()
265 };
266
267 let position = unsafe { &mut *position_ptr };
268 imp.insert_text(new_text, position);
269}
270
271unsafe extern "C" fn editable_delete_text<T: EditableImpl>(
272 editableptr: *mut ffi::GtkEditable,
273 start_pos: i32,
274 end_pos: i32,
275) {
276 assert!(!editableptr.is_null());
277
278 let instance = unsafe { &*(editableptr as *mut T::Instance) };
279 let imp = instance.imp();
280 imp.delete_text(start_pos, end_pos);
281}
282
283unsafe extern "C" fn editable_changed<T: EditableImpl>(editableptr: *mut ffi::GtkEditable) {
284 assert!(!editableptr.is_null());
285
286 let instance = unsafe { &*(editableptr as *mut T::Instance) };
287 let imp = instance.imp();
288 imp.changed();
289}
290
291unsafe extern "C" fn editable_do_insert_text<T: EditableImpl>(
292 editableptr: *mut ffi::GtkEditable,
293 new_text_ptr: *const glib::ffi::gchar,
294 new_text_length: i32,
295 position_ptr: *mut i32,
296) {
297 assert!(!editableptr.is_null());
298 assert!(!new_text_ptr.is_null());
299 assert!(!position_ptr.is_null());
300
301 let instance = unsafe { &*(editableptr as *mut T::Instance) };
302 let imp = instance.imp();
303
304 let new_text = if new_text_length < 0 {
305 unsafe { CStr::from_ptr(new_text_ptr).to_str().unwrap() }
306 } else {
307 let s = unsafe {
308 std::slice::from_raw_parts(new_text_ptr as *const _, new_text_length as usize)
309 };
310 str::from_utf8(s).unwrap()
311 };
312
313 let position = unsafe { &mut *position_ptr };
314 imp.do_insert_text(new_text, position);
315}
316
317unsafe extern "C" fn editable_do_delete_text<T: EditableImpl>(
318 editableptr: *mut ffi::GtkEditable,
319 start_pos: i32,
320 end_pos: i32,
321) {
322 assert!(!editableptr.is_null());
323
324 let instance = unsafe { &*(editableptr as *mut T::Instance) };
325 let imp = instance.imp();
326 imp.do_delete_text(start_pos, end_pos);
327}
328
329unsafe extern "C" fn editable_get_chars<T: EditableImpl>(
330 editableptr: *mut ffi::GtkEditable,
331 start_pos: i32,
332 end_pos: i32,
333) -> *mut glib::ffi::gchar {
334 assert!(!editableptr.is_null());
335
336 let instance = unsafe { &*(editableptr as *mut T::Instance) };
337 let imp = instance.imp();
338 imp.chars(start_pos, end_pos)
339 .map(|chars| chars.into_glib_ptr())
340 .unwrap_or(std::ptr::null_mut())
341}
342
343unsafe extern "C" fn editable_set_selection_bounds<T: EditableImpl>(
344 editableptr: *mut ffi::GtkEditable,
345 start_pos: i32,
346 end_pos: i32,
347) {
348 assert!(!editableptr.is_null());
349
350 let instance = unsafe { &*(editableptr as *mut T::Instance) };
351 let imp = instance.imp();
352 imp.set_selection_bounds(start_pos, end_pos);
353}
354
355unsafe extern "C" fn editable_get_selection_bounds<T: EditableImpl>(
356 editableptr: *mut ffi::GtkEditable,
357 start_pos_ptr: *mut i32,
358 end_pos_ptr: *mut i32,
359) -> glib::ffi::gboolean {
360 assert!(!editableptr.is_null());
361
362 let instance = unsafe { &*(editableptr as *mut T::Instance) };
363 let imp = instance.imp();
364
365 if let Some((start_pos, end_pos)) = imp.selection_bounds() {
366 if !start_pos_ptr.is_null() {
367 unsafe {
368 *start_pos_ptr = start_pos;
369 }
370 }
371 if !end_pos_ptr.is_null() {
372 unsafe {
373 *end_pos_ptr = end_pos;
374 }
375 }
376 glib::ffi::GTRUE
377 } else {
378 glib::ffi::GFALSE
379 }
380}
381
382unsafe extern "C" fn editable_set_position<T: EditableImpl>(
383 editableptr: *mut ffi::GtkEditable,
384 position: i32,
385) {
386 assert!(!editableptr.is_null());
387
388 let instance = unsafe { &*(editableptr as *mut T::Instance) };
389 let imp = instance.imp();
390 imp.set_position(position);
391}
392
393unsafe extern "C" fn editable_get_position<T: EditableImpl>(
394 editableptr: *mut ffi::GtkEditable,
395) -> i32 {
396 assert!(!editableptr.is_null());
397
398 let instance = unsafe { &*(editableptr as *mut T::Instance) };
399 let imp = instance.imp();
400 imp.position()
401}