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