Skip to main content

gtk/
text_buffer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::TextChildAnchor;
4use crate::TextIter;
5use crate::TextTag;
6use crate::{TextBuffer, ffi};
7use glib::object::{Cast, IsA};
8use glib::signal::{SignalHandlerId, connect_raw};
9use glib::translate::*;
10use libc::{c_char, c_int};
11use std::boxed::Box as Box_;
12use std::mem::transmute;
13use std::{slice, str};
14
15mod sealed {
16    pub trait Sealed {}
17    impl<T: glib::object::IsA<crate::TextBuffer>> Sealed for T {}
18}
19
20pub trait TextBufferExtManual: IsA<TextBuffer> + sealed::Sealed + 'static {
21    /// The ::apply-tag signal is emitted to apply a tag to a
22    /// range of text in a [`TextBuffer`][crate::TextBuffer].
23    /// Applying actually occurs in the default handler.
24    ///
25    /// Note that if your handler runs before the default handler it must not
26    /// invalidate the `start` and `end` iters (or has to revalidate them).
27    ///
28    /// See also:
29    /// [`TextBufferExt::apply_tag()`][crate::prelude::TextBufferExt::apply_tag()],
30    /// `gtk_text_buffer_insert_with_tags()`,
31    /// [`TextBufferExt::insert_range()`][crate::prelude::TextBufferExt::insert_range()].
32    /// ## `tag`
33    /// the applied tag
34    /// ## `start`
35    /// the start of the range the tag is applied to
36    /// ## `end`
37    /// the end of the range the tag is applied to
38    fn connect_apply_tag<F: Fn(&Self, &TextTag, &mut TextIter, &mut TextIter) + 'static>(
39        &self,
40        f: F,
41    ) -> SignalHandlerId {
42        unsafe extern "C" fn apply_tag_trampoline<
43            P,
44            F: Fn(&P, &TextTag, &mut TextIter, &mut TextIter) + 'static,
45        >(
46            this: *mut ffi::GtkTextBuffer,
47            tag: *mut ffi::GtkTextTag,
48            start: *mut ffi::GtkTextIter,
49            end: *mut ffi::GtkTextIter,
50            f: glib::ffi::gpointer,
51        ) where
52            P: IsA<TextBuffer>,
53        {
54            unsafe {
55                let f: &F = &*(f as *const F);
56                let mut start_copy = from_glib_none(start);
57                let mut end_copy = from_glib_none(end);
58
59                f(
60                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
61                    &from_glib_borrow(tag),
62                    &mut start_copy,
63                    &mut end_copy,
64                );
65
66                *start = *start_copy.to_glib_none().0;
67                *end = *end_copy.to_glib_none().0;
68            }
69        }
70        unsafe {
71            let f: Box_<F> = Box_::new(f);
72            connect_raw(
73                self.as_ptr() as *mut _,
74                c"apply-tag".as_ptr() as *const _,
75                Some(transmute::<*const (), unsafe extern "C" fn()>(
76                    apply_tag_trampoline::<Self, F> as *const (),
77                )),
78                Box_::into_raw(f),
79            )
80        }
81    }
82
83    /// The ::delete-range signal is emitted to delete a range
84    /// from a [`TextBuffer`][crate::TextBuffer].
85    ///
86    /// Note that if your handler runs before the default handler it must not
87    /// invalidate the `start` and `end` iters (or has to revalidate them).
88    /// The default signal handler revalidates the `start` and `end` iters to
89    /// both point to the location where text was deleted. Handlers
90    /// which run after the default handler (see `g_signal_connect_after()`)
91    /// do not have access to the deleted text.
92    ///
93    /// See also: [`TextBufferExt::delete()`][crate::prelude::TextBufferExt::delete()].
94    /// ## `start`
95    /// the start of the range to be deleted
96    /// ## `end`
97    /// the end of the range to be deleted
98    fn connect_delete_range<F: Fn(&Self, &mut TextIter, &mut TextIter) + 'static>(
99        &self,
100        f: F,
101    ) -> SignalHandlerId {
102        unsafe extern "C" fn delete_range_trampoline<
103            P,
104            F: Fn(&P, &mut TextIter, &mut TextIter) + 'static,
105        >(
106            this: *mut ffi::GtkTextBuffer,
107            start: *mut ffi::GtkTextIter,
108            end: *mut ffi::GtkTextIter,
109            f: glib::ffi::gpointer,
110        ) where
111            P: IsA<TextBuffer>,
112        {
113            unsafe {
114                let f: &F = &*(f as *const F);
115                let mut start_copy = from_glib_none(start);
116                let mut end_copy = from_glib_none(end);
117
118                f(
119                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
120                    &mut start_copy,
121                    &mut end_copy,
122                );
123
124                *start = *start_copy.to_glib_none().0;
125                *end = *end_copy.to_glib_none().0;
126            }
127        }
128        unsafe {
129            let f: Box_<F> = Box_::new(f);
130            connect_raw(
131                self.as_ptr() as *mut _,
132                c"delete-range".as_ptr() as *const _,
133                Some(transmute::<*const (), unsafe extern "C" fn()>(
134                    delete_range_trampoline::<Self, F> as *const (),
135                )),
136                Box_::into_raw(f),
137            )
138        }
139    }
140
141    /// The ::insert-child-anchor signal is emitted to insert a
142    /// [`TextChildAnchor`][crate::TextChildAnchor] in a [`TextBuffer`][crate::TextBuffer].
143    /// Insertion actually occurs in the default handler.
144    ///
145    /// Note that if your handler runs before the default handler it must
146    /// not invalidate the `location` iter (or has to revalidate it).
147    /// The default signal handler revalidates it to be placed after the
148    /// inserted `anchor`.
149    ///
150    /// See also: [`TextBufferExt::insert_child_anchor()`][crate::prelude::TextBufferExt::insert_child_anchor()].
151    /// ## `location`
152    /// position to insert `anchor` in `textbuffer`
153    /// ## `anchor`
154    /// the [`TextChildAnchor`][crate::TextChildAnchor] to be inserted
155    fn connect_insert_child_anchor<F: Fn(&Self, &mut TextIter, &TextChildAnchor) + 'static>(
156        &self,
157        f: F,
158    ) -> SignalHandlerId {
159        unsafe extern "C" fn insert_child_anchor_trampoline<
160            P,
161            F: Fn(&P, &mut TextIter, &TextChildAnchor) + 'static,
162        >(
163            this: *mut ffi::GtkTextBuffer,
164            location: *mut ffi::GtkTextIter,
165            anchor: *mut ffi::GtkTextChildAnchor,
166            f: glib::ffi::gpointer,
167        ) where
168            P: IsA<TextBuffer>,
169        {
170            unsafe {
171                let f: &F = &*(f as *const F);
172                let mut location_copy = from_glib_none(location);
173
174                f(
175                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
176                    &mut location_copy,
177                    &from_glib_borrow(anchor),
178                );
179
180                *location = *location_copy.to_glib_none().0;
181            }
182        }
183        unsafe {
184            let f: Box_<F> = Box_::new(f);
185            connect_raw(
186                self.as_ptr() as *mut _,
187                c"insert-child-anchor".as_ptr() as *const _,
188                Some(transmute::<*const (), unsafe extern "C" fn()>(
189                    insert_child_anchor_trampoline::<Self, F> as *const (),
190                )),
191                Box_::into_raw(f),
192            )
193        }
194    }
195
196    /// The ::insert-pixbuf signal is emitted to insert a [`gdk_pixbuf::Pixbuf`][crate::gdk_pixbuf::Pixbuf]
197    /// in a [`TextBuffer`][crate::TextBuffer]. Insertion actually occurs in the default handler.
198    ///
199    /// Note that if your handler runs before the default handler it must not
200    /// invalidate the `location` iter (or has to revalidate it).
201    /// The default signal handler revalidates it to be placed after the
202    /// inserted `pixbuf`.
203    ///
204    /// See also: [`TextBufferExt::insert_pixbuf()`][crate::prelude::TextBufferExt::insert_pixbuf()].
205    /// ## `location`
206    /// position to insert `pixbuf` in `textbuffer`
207    /// ## `pixbuf`
208    /// the [`gdk_pixbuf::Pixbuf`][crate::gdk_pixbuf::Pixbuf] to be inserted
209    fn connect_insert_pixbuf<F: Fn(&Self, &mut TextIter, &gdk_pixbuf::Pixbuf) + 'static>(
210        &self,
211        f: F,
212    ) -> SignalHandlerId {
213        unsafe extern "C" fn insert_pixbuf_trampoline<
214            P,
215            F: Fn(&P, &mut TextIter, &gdk_pixbuf::Pixbuf) + 'static,
216        >(
217            this: *mut ffi::GtkTextBuffer,
218            location: *mut ffi::GtkTextIter,
219            pixbuf: *mut gdk_pixbuf::ffi::GdkPixbuf,
220            f: glib::ffi::gpointer,
221        ) where
222            P: IsA<TextBuffer>,
223        {
224            unsafe {
225                let f: &F = &*(f as *const F);
226                let mut location_copy = from_glib_none(location);
227
228                f(
229                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
230                    &mut location_copy,
231                    &from_glib_borrow(pixbuf),
232                );
233
234                *location = *location_copy.to_glib_none().0;
235            }
236        }
237        unsafe {
238            let f: Box_<F> = Box_::new(f);
239            connect_raw(
240                self.as_ptr() as *mut _,
241                c"insert-pixbuf".as_ptr() as *const _,
242                Some(transmute::<*const (), unsafe extern "C" fn()>(
243                    insert_pixbuf_trampoline::<Self, F> as *const (),
244                )),
245                Box_::into_raw(f),
246            )
247        }
248    }
249
250    /// The ::insert-text signal is emitted to insert text in a [`TextBuffer`][crate::TextBuffer].
251    /// Insertion actually occurs in the default handler.
252    ///
253    /// Note that if your handler runs before the default handler it must not
254    /// invalidate the `location` iter (or has to revalidate it).
255    /// The default signal handler revalidates it to point to the end of the
256    /// inserted text.
257    ///
258    /// See also:
259    /// [`TextBufferExt::insert()`][crate::prelude::TextBufferExt::insert()],
260    /// [`TextBufferExt::insert_range()`][crate::prelude::TextBufferExt::insert_range()].
261    /// ## `location`
262    /// position to insert `text` in `textbuffer`
263    /// ## `text`
264    /// the UTF-8 text to be inserted
265    /// ## `len`
266    /// length of the inserted text in bytes
267    fn connect_insert_text<F: Fn(&Self, &mut TextIter, &str) + 'static>(
268        &self,
269        f: F,
270    ) -> SignalHandlerId {
271        unsafe extern "C" fn insert_text_trampoline<T, F: Fn(&T, &mut TextIter, &str) + 'static>(
272            this: *mut ffi::GtkTextBuffer,
273            location: *mut ffi::GtkTextIter,
274            text: *mut c_char,
275            len: c_int,
276            f: glib::ffi::gpointer,
277        ) where
278            T: IsA<TextBuffer>,
279        {
280            unsafe {
281                let f: &F = &*(f as *const F);
282                let mut location_copy = from_glib_none(location);
283
284                let text = if len <= 0 {
285                    &[]
286                } else {
287                    slice::from_raw_parts(text as *const u8, len as usize)
288                };
289
290                f(
291                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
292                    &mut location_copy,
293                    str::from_utf8(text).unwrap(),
294                );
295
296                *location = *location_copy.to_glib_none().0;
297            }
298        }
299        unsafe {
300            let f: Box_<F> = Box_::new(f);
301            connect_raw(
302                self.to_glib_none().0 as *mut _,
303                c"insert-text".as_ptr() as *mut _,
304                Some(transmute::<*const (), unsafe extern "C" fn()>(
305                    insert_text_trampoline::<Self, F> as *const (),
306                )),
307                Box_::into_raw(f),
308            )
309        }
310    }
311
312    /// The ::remove-tag signal is emitted to remove all occurrences of `tag` from
313    /// a range of text in a [`TextBuffer`][crate::TextBuffer].
314    /// Removal actually occurs in the default handler.
315    ///
316    /// Note that if your handler runs before the default handler it must not
317    /// invalidate the `start` and `end` iters (or has to revalidate them).
318    ///
319    /// See also:
320    /// [`TextBufferExt::remove_tag()`][crate::prelude::TextBufferExt::remove_tag()].
321    /// ## `tag`
322    /// the tag to be removed
323    /// ## `start`
324    /// the start of the range the tag is removed from
325    /// ## `end`
326    /// the end of the range the tag is removed from
327    fn connect_remove_tag<F: Fn(&Self, &TextTag, &mut TextIter, &mut TextIter) + 'static>(
328        &self,
329        f: F,
330    ) -> SignalHandlerId {
331        unsafe extern "C" fn remove_tag_trampoline<
332            P,
333            F: Fn(&P, &TextTag, &mut TextIter, &mut TextIter) + 'static,
334        >(
335            this: *mut ffi::GtkTextBuffer,
336            tag: *mut ffi::GtkTextTag,
337            start: *mut ffi::GtkTextIter,
338            end: *mut ffi::GtkTextIter,
339            f: glib::ffi::gpointer,
340        ) where
341            P: IsA<TextBuffer>,
342        {
343            unsafe {
344                let f: &F = &*(f as *const F);
345                let mut start_copy = from_glib_none(start);
346                let mut end_copy = from_glib_none(end);
347
348                f(
349                    TextBuffer::from_glib_borrow(this).unsafe_cast_ref(),
350                    &from_glib_borrow(tag),
351                    &mut start_copy,
352                    &mut end_copy,
353                );
354
355                *start = *start_copy.to_glib_none().0;
356                *end = *end_copy.to_glib_none().0;
357            }
358        }
359        unsafe {
360            let f: Box_<F> = Box_::new(f);
361            connect_raw(
362                self.as_ptr() as *mut _,
363                c"remove-tag".as_ptr() as *const _,
364                Some(transmute::<*const (), unsafe extern "C" fn()>(
365                    remove_tag_trampoline::<Self, F> as *const (),
366                )),
367                Box_::into_raw(f),
368            )
369        }
370    }
371}
372
373impl<O: IsA<TextBuffer>> TextBufferExtManual for O {}