Skip to main content

gtk/subclass/
editable.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for implementing the [`Editable`] interface.
5
6use 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}