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