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 {}