gtk4/subclass/
im_context.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 subclassing [`IMContext`].
5
6use glib::{translate::*, GString};
7use pango::AttrList;
8
9use crate::{ffi, prelude::*, subclass::prelude::*, IMContext, Widget};
10
11#[allow(clippy::upper_case_acronyms)]
12pub trait IMContextImpl: ObjectImpl + ObjectSubclass<Type: IsA<IMContext>> {
13    fn commit(&self, string: &str) {
14        self.parent_commit(string)
15    }
16    fn delete_surrounding(&self, offset: i32, n_chars: i32) -> bool {
17        self.parent_delete_surrounding(offset, n_chars)
18    }
19    fn filter_keypress(&self, event: &gdk::Event) -> bool {
20        self.parent_filter_keypress(event)
21    }
22    fn focus_in(&self) {
23        self.parent_focus_in()
24    }
25    fn focus_out(&self) {
26        self.parent_focus_out()
27    }
28    #[doc(alias = "get_preedit_string")]
29    fn preedit_string(&self) -> (GString, AttrList, i32) {
30        self.parent_preedit_string()
31    }
32    #[doc(alias = "get_surrounding")]
33    fn surrounding(&self) -> Option<(GString, i32)> {
34        self.parent_surrounding()
35    }
36    fn preedit_changed(&self) {
37        self.parent_preedit_changed()
38    }
39    fn preedit_end(&self) {
40        self.parent_preedit_end()
41    }
42    fn preedit_start(&self) {
43        self.parent_preedit_start()
44    }
45    fn reset(&self) {
46        self.parent_reset()
47    }
48    fn retrieve_surrounding(&self) -> bool {
49        self.parent_retrieve_surrounding()
50    }
51    fn set_client_widget<P: IsA<Widget>>(&self, widget: Option<&P>) {
52        self.parent_set_client_widget(widget)
53    }
54    fn set_cursor_location(&self, area: &gdk::Rectangle) {
55        self.parent_set_cursor_location(area)
56    }
57    #[cfg_attr(feature = "v4_2", deprecated = "Since 4.2")]
58    #[allow(deprecated)]
59    fn set_surrounding(&self, text: &str, cursor_index: i32) {
60        self.parent_set_surrounding(text, cursor_index)
61    }
62    fn set_use_preedit(&self, use_preedit: bool) {
63        self.parent_set_use_preedit(use_preedit)
64    }
65    #[cfg(feature = "v4_10")]
66    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
67    fn activate_osk(&self) {
68        self.parent_activate_osk()
69    }
70    #[cfg(feature = "v4_14")]
71    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
72    fn activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
73        self.parent_activate_osk_with_event(event)
74    }
75}
76
77#[allow(clippy::upper_case_acronyms)]
78pub trait IMContextImplExt: IMContextImpl {
79    fn parent_commit(&self, string: &str) {
80        unsafe {
81            let data = Self::type_data();
82            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
83            if let Some(f) = (*parent_class).commit {
84                f(
85                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
86                    string.to_glib_none().0,
87                );
88            }
89        }
90    }
91
92    // Returns true if the signal was handled
93    fn parent_delete_surrounding(&self, offset: i32, n_chars: i32) -> bool {
94        unsafe {
95            let data = Self::type_data();
96            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
97            if let Some(f) = (*parent_class).delete_surrounding {
98                from_glib(f(
99                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
100                    offset,
101                    n_chars,
102                ))
103            } else {
104                false
105            }
106        }
107    }
108
109    // Returns true if the event was consumed
110    fn parent_filter_keypress(&self, event: &gdk::Event) -> bool {
111        unsafe {
112            let data = Self::type_data();
113            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
114            if let Some(f) = (*parent_class).filter_keypress {
115                from_glib(f(
116                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
117                    event.to_glib_none().0,
118                ))
119            } else {
120                false
121            }
122        }
123    }
124
125    fn parent_focus_in(&self) {
126        unsafe {
127            let data = Self::type_data();
128            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
129            if let Some(f) = (*parent_class).focus_in {
130                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
131            }
132        }
133    }
134
135    fn parent_focus_out(&self) {
136        unsafe {
137            let data = Self::type_data();
138            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
139            if let Some(f) = (*parent_class).focus_out {
140                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
141            }
142        }
143    }
144
145    fn parent_surrounding(&self) -> Option<(GString, i32)> {
146        unsafe {
147            let data = Self::type_data();
148            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
149            if let Some(f) = (*parent_class).get_surrounding {
150                let mut text = std::ptr::null_mut();
151                let mut cursor_index = std::mem::MaybeUninit::uninit();
152                let ret = from_glib(f(
153                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
154                    &mut text,
155                    cursor_index.as_mut_ptr(),
156                ));
157                if ret {
158                    return Some((from_glib_full(text), cursor_index.assume_init()));
159                }
160            }
161            None
162        }
163    }
164
165    fn parent_preedit_string(&self) -> (GString, AttrList, i32) {
166        unsafe {
167            let data = Self::type_data();
168            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
169            let f = (*parent_class)
170                .get_preedit_string
171                .expect("No parent class impl for \"get_preedit_string\"");
172            let mut string = std::ptr::null_mut();
173            let mut attrs = std::ptr::null_mut();
174            let mut cursor_pos = std::mem::MaybeUninit::uninit();
175            f(
176                self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
177                &mut string,
178                &mut attrs,
179                cursor_pos.as_mut_ptr(),
180            );
181            (
182                from_glib_full(string),
183                from_glib_full(attrs),
184                cursor_pos.assume_init(),
185            )
186        }
187    }
188
189    fn parent_preedit_changed(&self) {
190        unsafe {
191            let data = Self::type_data();
192            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
193            if let Some(f) = (*parent_class).preedit_changed {
194                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
195            }
196        }
197    }
198
199    fn parent_preedit_end(&self) {
200        unsafe {
201            let data = Self::type_data();
202            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
203            if let Some(f) = (*parent_class).preedit_end {
204                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
205            }
206        }
207    }
208
209    fn parent_preedit_start(&self) {
210        unsafe {
211            let data = Self::type_data();
212            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
213            if let Some(f) = (*parent_class).preedit_start {
214                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
215            }
216        }
217    }
218
219    fn parent_reset(&self) {
220        unsafe {
221            let data = Self::type_data();
222            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
223            if let Some(f) = (*parent_class).reset {
224                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
225            }
226        }
227    }
228
229    // Returns true if the signal was handled
230    fn parent_retrieve_surrounding(&self) -> bool {
231        unsafe {
232            let data = Self::type_data();
233            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
234            if let Some(f) = (*parent_class).retrieve_surrounding {
235                from_glib(f(self
236                    .obj()
237                    .unsafe_cast_ref::<IMContext>()
238                    .to_glib_none()
239                    .0))
240            } else {
241                false
242            }
243        }
244    }
245
246    fn parent_set_client_widget<P: IsA<Widget>>(&self, widget: Option<&P>) {
247        unsafe {
248            let data = Self::type_data();
249            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
250            if let Some(f) = (*parent_class).set_client_widget {
251                f(
252                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
253                    widget.map(|p| p.as_ref()).to_glib_none().0,
254                )
255            }
256        }
257    }
258
259    fn parent_set_cursor_location(&self, area: &gdk::Rectangle) {
260        unsafe {
261            let data = Self::type_data();
262            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
263            if let Some(f) = (*parent_class).set_cursor_location {
264                f(
265                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
266                    area.to_glib_none().0 as *mut _,
267                );
268            }
269        }
270    }
271
272    #[cfg_attr(feature = "v4_2", deprecated = "Since 4.2")]
273    #[allow(deprecated)]
274    fn parent_set_surrounding(&self, text: &str, cursor_index: i32) {
275        unsafe {
276            let data = Self::type_data();
277            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
278            if let Some(f) = (*parent_class).set_surrounding {
279                f(
280                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
281                    text.to_glib_none().0,
282                    text.len() as i32,
283                    cursor_index,
284                )
285            }
286        }
287    }
288
289    fn parent_set_use_preedit(&self, use_preedit: bool) {
290        unsafe {
291            let data = Self::type_data();
292            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
293            if let Some(f) = (*parent_class).set_use_preedit {
294                f(
295                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
296                    use_preedit.into_glib(),
297                )
298            }
299        }
300    }
301
302    #[cfg(feature = "v4_10")]
303    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
304    fn parent_activate_osk(&self) {
305        unsafe {
306            let data = Self::type_data();
307            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
308            if let Some(f) = (*parent_class).activate_osk {
309                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
310            }
311        }
312    }
313
314    #[cfg(feature = "v4_14")]
315    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
316    fn parent_activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
317        unsafe {
318            let data = Self::type_data();
319            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
320            if let Some(f) = (*parent_class).activate_osk_with_event {
321                from_glib(f(
322                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
323                    event.to_glib_none().0,
324                ))
325            } else {
326                false
327            }
328        }
329    }
330}
331
332impl<T: IMContextImpl> IMContextImplExt for T {}
333
334unsafe impl<T: IMContextImpl> IsSubclassable<T> for IMContext {
335    fn class_init(class: &mut glib::Class<Self>) {
336        Self::parent_class_init::<T>(class);
337
338        assert_initialized_main_thread!();
339
340        let klass = class.as_mut();
341        klass.commit = Some(im_context_commit::<T>);
342        klass.delete_surrounding = Some(im_context_delete_surrounding::<T>);
343        klass.filter_keypress = Some(im_context_filter_keypress::<T>);
344        klass.focus_in = Some(im_context_focus_in::<T>);
345        klass.focus_out = Some(im_context_focus_out::<T>);
346        klass.get_preedit_string = Some(im_context_get_preedit_string::<T>);
347        klass.get_surrounding = Some(im_context_get_surrounding::<T>);
348        klass.preedit_changed = Some(im_context_preedit_changed::<T>);
349        klass.preedit_end = Some(im_context_preedit_end::<T>);
350        klass.preedit_start = Some(im_context_preedit_start::<T>);
351        klass.reset = Some(im_context_reset::<T>);
352        klass.retrieve_surrounding = Some(im_context_retrieve_surrounding::<T>);
353        klass.set_client_widget = Some(im_context_set_client_widget::<T>);
354        klass.set_cursor_location = Some(im_context_set_cursor_location::<T>);
355        klass.set_surrounding = Some(im_context_set_surrounding::<T>);
356        klass.set_use_preedit = Some(im_context_set_use_preedit::<T>);
357        #[cfg(feature = "v4_10")]
358        #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
359        {
360            klass.activate_osk = Some(im_context_activate_osk::<T>);
361        };
362        #[cfg(feature = "v4_14")]
363        #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
364        {
365            klass.activate_osk_with_event = Some(im_context_activate_osk_with_event::<T>);
366        };
367    }
368}
369
370unsafe extern "C" fn im_context_commit<T: IMContextImpl>(
371    ptr: *mut ffi::GtkIMContext,
372    stringptr: *const libc::c_char,
373) {
374    let instance = &*(ptr as *mut T::Instance);
375    let imp = instance.imp();
376    let string: Borrowed<GString> = from_glib_borrow(stringptr);
377
378    imp.commit(string.as_str())
379}
380
381unsafe extern "C" fn im_context_delete_surrounding<T: IMContextImpl>(
382    ptr: *mut ffi::GtkIMContext,
383    offset: i32,
384    n_chars: i32,
385) -> glib::ffi::gboolean {
386    let instance = &*(ptr as *mut T::Instance);
387    let imp = instance.imp();
388
389    imp.delete_surrounding(offset, n_chars).into_glib()
390}
391
392unsafe extern "C" fn im_context_filter_keypress<T: IMContextImpl>(
393    ptr: *mut ffi::GtkIMContext,
394    eventptr: *mut gdk::ffi::GdkEvent,
395) -> glib::ffi::gboolean {
396    let instance = &*(ptr as *mut T::Instance);
397    let imp = instance.imp();
398    let event: Borrowed<gdk::Event> = from_glib_borrow(eventptr);
399    imp.filter_keypress(&event).into_glib()
400}
401
402unsafe extern "C" fn im_context_focus_in<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
403    let instance = &*(ptr as *mut T::Instance);
404    let imp = instance.imp();
405
406    imp.focus_in()
407}
408
409unsafe extern "C" fn im_context_focus_out<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
410    let instance = &*(ptr as *mut T::Instance);
411    let imp = instance.imp();
412
413    imp.focus_out()
414}
415
416unsafe extern "C" fn im_context_get_preedit_string<T: IMContextImpl>(
417    ptr: *mut ffi::GtkIMContext,
418    text_ptr: *mut *mut libc::c_char,
419    attrs_ptr: *mut *mut pango::ffi::PangoAttrList,
420    cursor_index_ptr: *mut libc::c_int,
421) {
422    let instance = &*(ptr as *mut T::Instance);
423    let imp = instance.imp();
424
425    let (text, attrs, cursor_idx) = imp.preedit_string();
426
427    *text_ptr = text.into_glib_ptr();
428    *cursor_index_ptr = cursor_idx;
429    *attrs_ptr = attrs.into_glib_ptr();
430}
431
432unsafe extern "C" fn im_context_get_surrounding<T: IMContextImpl>(
433    ptr: *mut ffi::GtkIMContext,
434    text_ptr: *mut *mut libc::c_char,
435    cursor_index_ptr: *mut libc::c_int,
436) -> glib::ffi::gboolean {
437    let instance = &*(ptr as *mut T::Instance);
438    let imp = instance.imp();
439
440    if let Some((text, cursor_idx)) = imp.surrounding() {
441        *text_ptr = text.into_glib_ptr();
442        *cursor_index_ptr = cursor_idx;
443        true.into_glib()
444    } else {
445        *text_ptr = std::ptr::null_mut();
446        *cursor_index_ptr = 0;
447        false.into_glib()
448    }
449}
450
451unsafe extern "C" fn im_context_preedit_changed<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
452    let instance = &*(ptr as *mut T::Instance);
453    let imp = instance.imp();
454
455    imp.preedit_changed()
456}
457
458unsafe extern "C" fn im_context_preedit_end<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
459    let instance = &*(ptr as *mut T::Instance);
460    let imp = instance.imp();
461
462    imp.preedit_end()
463}
464
465unsafe extern "C" fn im_context_preedit_start<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
466    let instance = &*(ptr as *mut T::Instance);
467    let imp = instance.imp();
468
469    imp.preedit_start()
470}
471
472unsafe extern "C" fn im_context_reset<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
473    let instance = &*(ptr as *mut T::Instance);
474    let imp = instance.imp();
475
476    imp.reset()
477}
478
479unsafe extern "C" fn im_context_retrieve_surrounding<T: IMContextImpl>(
480    ptr: *mut ffi::GtkIMContext,
481) -> glib::ffi::gboolean {
482    let instance = &*(ptr as *mut T::Instance);
483    let imp = instance.imp();
484
485    imp.retrieve_surrounding().into_glib()
486}
487
488unsafe extern "C" fn im_context_set_client_widget<T: IMContextImpl>(
489    ptr: *mut ffi::GtkIMContext,
490    widgetptr: *mut ffi::GtkWidget,
491) {
492    let instance = &*(ptr as *mut T::Instance);
493    let imp = instance.imp();
494    let widget: Borrowed<Option<Widget>> = from_glib_borrow(widgetptr);
495
496    imp.set_client_widget(widget.as_ref().as_ref());
497}
498
499unsafe extern "C" fn im_context_set_cursor_location<T: IMContextImpl>(
500    ptr: *mut ffi::GtkIMContext,
501    areaptr: *mut gdk::ffi::GdkRectangle,
502) {
503    let instance = &*(ptr as *mut T::Instance);
504    let imp = instance.imp();
505    let area = from_glib_borrow(areaptr);
506
507    imp.set_cursor_location(&area);
508}
509
510unsafe extern "C" fn im_context_set_surrounding<T: IMContextImpl>(
511    ptr: *mut ffi::GtkIMContext,
512    textptr: *const libc::c_char,
513    length: i32,
514    cursor_index: i32,
515) {
516    let instance = &*(ptr as *mut T::Instance);
517    let imp = instance.imp();
518    let text: Borrowed<GString> = from_glib_borrow(textptr);
519
520    // length == -1 if text is null-terminated
521    let text = if length == -1 {
522        &text[..]
523    } else {
524        &text[0..(length as usize)]
525    };
526
527    imp.set_surrounding(text, cursor_index)
528}
529
530unsafe extern "C" fn im_context_set_use_preedit<T: IMContextImpl>(
531    ptr: *mut ffi::GtkIMContext,
532    use_preedit: glib::ffi::gboolean,
533) {
534    let instance = &*(ptr as *mut T::Instance);
535    let imp = instance.imp();
536
537    imp.set_use_preedit(from_glib(use_preedit))
538}
539
540#[cfg(feature = "v4_10")]
541#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
542unsafe extern "C" fn im_context_activate_osk<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
543    let instance = &*(ptr as *mut T::Instance);
544    let imp = instance.imp();
545
546    imp.activate_osk()
547}
548
549#[cfg(feature = "v4_14")]
550#[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
551unsafe extern "C" fn im_context_activate_osk_with_event<T: IMContextImpl>(
552    ptr: *mut ffi::GtkIMContext,
553    eventptr: *mut gdk::ffi::GdkEvent,
554) -> glib::ffi::gboolean {
555    let instance = &*(ptr as *mut T::Instance);
556    let imp = instance.imp();
557
558    let event: Borrowed<Option<gdk::Event>> = from_glib_borrow(eventptr);
559
560    imp.activate_osk_with_event(event.as_ref().as_ref())
561        .into_glib()
562}