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    /// Default handler of the [`commit`][struct@crate::IMContext#commit] signal.
14    fn commit(&self, string: &str) {
15        self.parent_commit(string)
16    }
17    /// Asks the widget that the input context is attached to delete
18    /// characters around the cursor position by emitting the
19    /// `::delete_surrounding` signal.
20    ///
21    /// Note that @offset and @n_chars are in characters not in bytes
22    /// which differs from the usage other places in [`IMContext`][crate::IMContext].
23    ///
24    /// In order to use this function, you should first call
25    /// [`IMContextExt::surrounding()`][crate::prelude::IMContextExt::surrounding()] to get the current context,
26    /// and call this function immediately afterwards to make sure that you
27    /// know what you are deleting. You should also account for the fact
28    /// that even if the signal was handled, the input context might not
29    /// have deleted all the characters that were requested to be deleted.
30    ///
31    /// This function is used by an input method that wants to make
32    /// substitutions in the existing text in response to new input.
33    /// It is not useful for applications.
34    /// ## `offset`
35    /// offset from cursor position in chars;
36    ///    a negative value means start before the cursor.
37    /// ## `n_chars`
38    /// number of characters to delete.
39    ///
40    /// # Returns
41    ///
42    /// [`true`] if the signal was handled.
43    fn delete_surrounding(&self, offset: i32, n_chars: i32) -> bool {
44        self.parent_delete_surrounding(offset, n_chars)
45    }
46    /// Allow an input method to internally handle key press and release
47    /// events.
48    ///
49    /// If this function returns [`true`], then no further processing
50    /// should be done for this key event.
51    /// ## `event`
52    /// the key event
53    ///
54    /// # Returns
55    ///
56    /// [`true`] if the input method handled the key event.
57    fn filter_keypress(&self, event: &gdk::Event) -> bool {
58        self.parent_filter_keypress(event)
59    }
60    /// Notify the input method that the widget to which this
61    /// input context corresponds has gained focus.
62    ///
63    /// The input method may, for example, change the displayed
64    /// feedback to reflect this change.
65    fn focus_in(&self) {
66        self.parent_focus_in()
67    }
68    /// Notify the input method that the widget to which this
69    /// input context corresponds has lost focus.
70    ///
71    /// The input method may, for example, change the displayed
72    /// feedback or reset the contexts state to reflect this change.
73    fn focus_out(&self) {
74        self.parent_focus_out()
75    }
76    /// Retrieve the current preedit string for the input context,
77    /// and a list of attributes to apply to the string.
78    ///
79    /// This string should be displayed inserted at the insertion point.
80    ///
81    /// # Returns
82    ///
83    ///
84    /// ## `str`
85    /// location to store the retrieved
86    ///   string. The string retrieved must be freed with g_free().
87    ///
88    /// ## `attrs`
89    /// location to store the retrieved
90    ///   attribute list. When you are done with this list, you
91    ///   must unreference it with `Pango::AttrList::unref()`.
92    ///
93    /// ## `cursor_pos`
94    /// location to store position of cursor
95    ///   (in characters) within the preedit string.
96    #[doc(alias = "get_preedit_string")]
97    fn preedit_string(&self) -> (GString, AttrList, i32) {
98        self.parent_preedit_string()
99    }
100    /// Retrieves context around the insertion point.
101    ///
102    /// Input methods typically want context in order to constrain input text
103    /// based on existing text; this is important for languages such as Thai
104    /// where only some sequences of characters are allowed.
105    ///
106    /// This function is implemented by emitting the
107    /// [`retrieve-surrounding`][struct@crate::IMContext#retrieve-surrounding] signal on the input method;
108    /// in response to this signal, a widget should provide as much context as
109    /// is available, up to an entire paragraph, by calling
110    /// [`IMContextExt::set_surrounding()`][crate::prelude::IMContextExt::set_surrounding()].
111    ///
112    /// Note that there is no obligation for a widget to respond to the
113    /// `::retrieve-surrounding` signal, so input methods must be prepared to
114    /// function without context.
115    ///
116    /// # Deprecated since 4.2
117    ///
118    /// Use [`IMContextExt::surrounding_with_selection()`][crate::prelude::IMContextExt::surrounding_with_selection()] instead.
119    ///
120    /// # Returns
121    ///
122    /// `TRUE` if surrounding text was provided; in this case
123    ///    you must free the result stored in `text`.
124    ///
125    /// ## `text`
126    /// location to store a UTF-8 encoded
127    ///   string of text holding context around the insertion point.
128    ///   If the function returns [`true`], then you must free the result
129    ///   stored in this location with g_free().
130    ///
131    /// ## `cursor_index`
132    /// location to store byte index of the insertion
133    ///   cursor within @text.
134    #[doc(alias = "get_surrounding")]
135    fn surrounding(&self) -> Option<(GString, i32)> {
136        self.parent_surrounding()
137    }
138    /// Default handler of the [`preedit-changed`][struct@crate::IMContext#preedit-changed]
139    ///   signal.
140    fn preedit_changed(&self) {
141        self.parent_preedit_changed()
142    }
143    /// Default handler of the [`preedit-end`][struct@crate::IMContext#preedit-end] signal.
144    fn preedit_end(&self) {
145        self.parent_preedit_end()
146    }
147    /// Default handler of the [`preedit-start`][struct@crate::IMContext#preedit-start] signal.
148    fn preedit_start(&self) {
149        self.parent_preedit_start()
150    }
151    /// Notify the input method that a change such as a change in cursor
152    /// position has been made.
153    ///
154    /// This will typically cause the input method to clear the preedit state.
155    fn reset(&self) {
156        self.parent_reset()
157    }
158    /// Default handler of the
159    ///   [`retrieve-surrounding`][struct@crate::IMContext#retrieve-surrounding] signal.
160    fn retrieve_surrounding(&self) -> bool {
161        self.parent_retrieve_surrounding()
162    }
163    /// Set the client widget for the input context.
164    ///
165    /// This is the [`Widget`][crate::Widget] holding the input focus. This widget is
166    /// used in order to correctly position status windows, and may
167    /// also be used for purposes internal to the input method.
168    /// ## `widget`
169    /// the client widget. This may be [`None`] to indicate
170    ///   that the previous client widget no longer exists.
171    fn set_client_widget<P: IsA<Widget>>(&self, widget: Option<&P>) {
172        self.parent_set_client_widget(widget)
173    }
174    /// Notify the input method that a change in cursor
175    /// position has been made.
176    ///
177    /// The location is relative to the client widget.
178    /// ## `area`
179    /// new location
180    fn set_cursor_location(&self, area: &gdk::Rectangle) {
181        self.parent_set_cursor_location(area)
182    }
183    /// Sets surrounding context around the insertion point and preedit
184    /// string.
185    ///
186    /// This function is expected to be called in response to the
187    /// [`retrieve-surrounding`][struct@crate::IMContext#retrieve-surrounding] signal, and will
188    /// likely have no effect if called at other times.
189    ///
190    /// # Deprecated since 4.2
191    ///
192    /// Use [`IMContextExt::set_surrounding_with_selection()`][crate::prelude::IMContextExt::set_surrounding_with_selection()] instead
193    /// ## `text`
194    /// text surrounding the insertion point, as UTF-8.
195    ///   the preedit string should not be included within @text
196    /// ## `len`
197    /// the length of @text, or -1 if @text is nul-terminated
198    /// ## `cursor_index`
199    /// the byte index of the insertion cursor within @text.
200    #[cfg_attr(feature = "v4_2", deprecated = "Since 4.2")]
201    #[allow(deprecated)]
202    fn set_surrounding(&self, text: &str, cursor_index: i32) {
203        self.parent_set_surrounding(text, cursor_index)
204    }
205    /// Sets whether the IM context should use the preedit string
206    /// to display feedback.
207    ///
208    /// If @use_preedit is [`false`] (default is [`true`]), then the IM context
209    /// may use some other method to display feedback, such as displaying
210    /// it in a child of the root window.
211    /// ## `use_preedit`
212    /// whether the IM context should use the preedit string.
213    fn set_use_preedit(&self, use_preedit: bool) {
214        self.parent_set_use_preedit(use_preedit)
215    }
216    #[cfg(feature = "v4_10")]
217    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
218    fn activate_osk(&self) {
219        self.parent_activate_osk()
220    }
221    #[cfg(feature = "v4_14")]
222    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
223    fn activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
224        self.parent_activate_osk_with_event(event)
225    }
226    /// Default handler of the
227    ///   [`invalid-composition`][struct@crate::IMContext#invalid-composition] signal. Since: 4.22
228    #[cfg(feature = "v4_22")]
229    #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
230    fn invalid_composition(&self, string: &str) -> bool {
231        self.parent_invalid_composition(string)
232    }
233}
234
235#[allow(clippy::upper_case_acronyms)]
236pub trait IMContextImplExt: IMContextImpl {
237    fn parent_commit(&self, string: &str) {
238        unsafe {
239            let data = Self::type_data();
240            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
241            if let Some(f) = (*parent_class).commit {
242                f(
243                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
244                    string.to_glib_none().0,
245                );
246            }
247        }
248    }
249
250    // Returns true if the signal was handled
251    fn parent_delete_surrounding(&self, offset: i32, n_chars: i32) -> bool {
252        unsafe {
253            let data = Self::type_data();
254            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
255            if let Some(f) = (*parent_class).delete_surrounding {
256                from_glib(f(
257                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
258                    offset,
259                    n_chars,
260                ))
261            } else {
262                false
263            }
264        }
265    }
266
267    // Returns true if the event was consumed
268    fn parent_filter_keypress(&self, event: &gdk::Event) -> bool {
269        unsafe {
270            let data = Self::type_data();
271            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
272            if let Some(f) = (*parent_class).filter_keypress {
273                from_glib(f(
274                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
275                    event.to_glib_none().0,
276                ))
277            } else {
278                false
279            }
280        }
281    }
282
283    fn parent_focus_in(&self) {
284        unsafe {
285            let data = Self::type_data();
286            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
287            if let Some(f) = (*parent_class).focus_in {
288                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
289            }
290        }
291    }
292
293    fn parent_focus_out(&self) {
294        unsafe {
295            let data = Self::type_data();
296            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
297            if let Some(f) = (*parent_class).focus_out {
298                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
299            }
300        }
301    }
302
303    fn parent_surrounding(&self) -> Option<(GString, i32)> {
304        unsafe {
305            let data = Self::type_data();
306            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
307            if let Some(f) = (*parent_class).get_surrounding {
308                let mut text = std::ptr::null_mut();
309                let mut cursor_index = std::mem::MaybeUninit::uninit();
310                let ret = from_glib(f(
311                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
312                    &mut text,
313                    cursor_index.as_mut_ptr(),
314                ));
315                if ret {
316                    return Some((from_glib_full(text), cursor_index.assume_init()));
317                }
318            }
319            None
320        }
321    }
322
323    fn parent_preedit_string(&self) -> (GString, AttrList, i32) {
324        unsafe {
325            let data = Self::type_data();
326            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
327            let f = (*parent_class)
328                .get_preedit_string
329                .expect("No parent class impl for \"get_preedit_string\"");
330            let mut string = std::ptr::null_mut();
331            let mut attrs = std::ptr::null_mut();
332            let mut cursor_pos = std::mem::MaybeUninit::uninit();
333            f(
334                self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
335                &mut string,
336                &mut attrs,
337                cursor_pos.as_mut_ptr(),
338            );
339            (
340                from_glib_full(string),
341                from_glib_full(attrs),
342                cursor_pos.assume_init(),
343            )
344        }
345    }
346
347    fn parent_preedit_changed(&self) {
348        unsafe {
349            let data = Self::type_data();
350            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
351            if let Some(f) = (*parent_class).preedit_changed {
352                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
353            }
354        }
355    }
356
357    fn parent_preedit_end(&self) {
358        unsafe {
359            let data = Self::type_data();
360            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
361            if let Some(f) = (*parent_class).preedit_end {
362                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
363            }
364        }
365    }
366
367    fn parent_preedit_start(&self) {
368        unsafe {
369            let data = Self::type_data();
370            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
371            if let Some(f) = (*parent_class).preedit_start {
372                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
373            }
374        }
375    }
376
377    fn parent_reset(&self) {
378        unsafe {
379            let data = Self::type_data();
380            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
381            if let Some(f) = (*parent_class).reset {
382                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
383            }
384        }
385    }
386
387    // Returns true if the signal was handled
388    fn parent_retrieve_surrounding(&self) -> bool {
389        unsafe {
390            let data = Self::type_data();
391            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
392            if let Some(f) = (*parent_class).retrieve_surrounding {
393                from_glib(f(self
394                    .obj()
395                    .unsafe_cast_ref::<IMContext>()
396                    .to_glib_none()
397                    .0))
398            } else {
399                false
400            }
401        }
402    }
403
404    fn parent_set_client_widget<P: IsA<Widget>>(&self, widget: Option<&P>) {
405        unsafe {
406            let data = Self::type_data();
407            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
408            if let Some(f) = (*parent_class).set_client_widget {
409                f(
410                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
411                    widget.map(|p| p.as_ref()).to_glib_none().0,
412                )
413            }
414        }
415    }
416
417    fn parent_set_cursor_location(&self, area: &gdk::Rectangle) {
418        unsafe {
419            let data = Self::type_data();
420            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
421            if let Some(f) = (*parent_class).set_cursor_location {
422                f(
423                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
424                    area.to_glib_none().0 as *mut _,
425                );
426            }
427        }
428    }
429
430    #[cfg_attr(feature = "v4_2", deprecated = "Since 4.2")]
431    #[allow(deprecated)]
432    fn parent_set_surrounding(&self, text: &str, cursor_index: i32) {
433        unsafe {
434            let data = Self::type_data();
435            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
436            if let Some(f) = (*parent_class).set_surrounding {
437                f(
438                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
439                    text.to_glib_none().0,
440                    text.len() as i32,
441                    cursor_index,
442                )
443            }
444        }
445    }
446
447    fn parent_set_use_preedit(&self, use_preedit: bool) {
448        unsafe {
449            let data = Self::type_data();
450            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
451            if let Some(f) = (*parent_class).set_use_preedit {
452                f(
453                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
454                    use_preedit.into_glib(),
455                )
456            }
457        }
458    }
459
460    #[cfg(feature = "v4_10")]
461    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
462    fn parent_activate_osk(&self) {
463        unsafe {
464            let data = Self::type_data();
465            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
466            if let Some(f) = (*parent_class).activate_osk {
467                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
468            }
469        }
470    }
471
472    #[cfg(feature = "v4_14")]
473    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
474    fn parent_activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
475        unsafe {
476            let data = Self::type_data();
477            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
478            if let Some(f) = (*parent_class).activate_osk_with_event {
479                from_glib(f(
480                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
481                    event.to_glib_none().0,
482                ))
483            } else {
484                false
485            }
486        }
487    }
488
489    #[cfg(feature = "v4_22")]
490    #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
491    fn parent_invalid_composition(&self, string: &str) -> bool {
492        unsafe {
493            let data = Self::type_data();
494            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
495            if let Some(f) = (*parent_class).invalid_composition {
496                from_glib(f(
497                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
498                    string.to_glib_none().0,
499                ))
500            } else {
501                false
502            }
503        }
504    }
505}
506
507impl<T: IMContextImpl> IMContextImplExt for T {}
508
509unsafe impl<T: IMContextImpl> IsSubclassable<T> for IMContext {
510    fn class_init(class: &mut glib::Class<Self>) {
511        Self::parent_class_init::<T>(class);
512
513        assert_initialized_main_thread!();
514
515        let klass = class.as_mut();
516        klass.commit = Some(im_context_commit::<T>);
517        klass.delete_surrounding = Some(im_context_delete_surrounding::<T>);
518        klass.filter_keypress = Some(im_context_filter_keypress::<T>);
519        klass.focus_in = Some(im_context_focus_in::<T>);
520        klass.focus_out = Some(im_context_focus_out::<T>);
521        klass.get_preedit_string = Some(im_context_get_preedit_string::<T>);
522        klass.get_surrounding = Some(im_context_get_surrounding::<T>);
523        klass.preedit_changed = Some(im_context_preedit_changed::<T>);
524        klass.preedit_end = Some(im_context_preedit_end::<T>);
525        klass.preedit_start = Some(im_context_preedit_start::<T>);
526        klass.reset = Some(im_context_reset::<T>);
527        klass.retrieve_surrounding = Some(im_context_retrieve_surrounding::<T>);
528        klass.set_client_widget = Some(im_context_set_client_widget::<T>);
529        klass.set_cursor_location = Some(im_context_set_cursor_location::<T>);
530        klass.set_surrounding = Some(im_context_set_surrounding::<T>);
531        klass.set_use_preedit = Some(im_context_set_use_preedit::<T>);
532        #[cfg(feature = "v4_10")]
533        #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
534        {
535            klass.activate_osk = Some(im_context_activate_osk::<T>);
536        };
537        #[cfg(feature = "v4_14")]
538        #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
539        {
540            klass.activate_osk_with_event = Some(im_context_activate_osk_with_event::<T>);
541        };
542        #[cfg(feature = "v4_22")]
543        #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
544        {
545            klass.invalid_composition = Some(im_context_invalid_composition::<T>);
546        };
547    }
548}
549
550unsafe extern "C" fn im_context_commit<T: IMContextImpl>(
551    ptr: *mut ffi::GtkIMContext,
552    stringptr: *const libc::c_char,
553) {
554    let instance = &*(ptr as *mut T::Instance);
555    let imp = instance.imp();
556    let string: Borrowed<GString> = from_glib_borrow(stringptr);
557
558    imp.commit(string.as_str())
559}
560
561unsafe extern "C" fn im_context_delete_surrounding<T: IMContextImpl>(
562    ptr: *mut ffi::GtkIMContext,
563    offset: i32,
564    n_chars: i32,
565) -> glib::ffi::gboolean {
566    let instance = &*(ptr as *mut T::Instance);
567    let imp = instance.imp();
568
569    imp.delete_surrounding(offset, n_chars).into_glib()
570}
571
572unsafe extern "C" fn im_context_filter_keypress<T: IMContextImpl>(
573    ptr: *mut ffi::GtkIMContext,
574    eventptr: *mut gdk::ffi::GdkEvent,
575) -> glib::ffi::gboolean {
576    let instance = &*(ptr as *mut T::Instance);
577    let imp = instance.imp();
578    let event: Borrowed<gdk::Event> = from_glib_borrow(eventptr);
579    imp.filter_keypress(&event).into_glib()
580}
581
582unsafe extern "C" fn im_context_focus_in<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
583    let instance = &*(ptr as *mut T::Instance);
584    let imp = instance.imp();
585
586    imp.focus_in()
587}
588
589unsafe extern "C" fn im_context_focus_out<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
590    let instance = &*(ptr as *mut T::Instance);
591    let imp = instance.imp();
592
593    imp.focus_out()
594}
595
596unsafe extern "C" fn im_context_get_preedit_string<T: IMContextImpl>(
597    ptr: *mut ffi::GtkIMContext,
598    text_ptr: *mut *mut libc::c_char,
599    attrs_ptr: *mut *mut pango::ffi::PangoAttrList,
600    cursor_index_ptr: *mut libc::c_int,
601) {
602    let instance = &*(ptr as *mut T::Instance);
603    let imp = instance.imp();
604
605    let (text, attrs, cursor_idx) = imp.preedit_string();
606
607    *text_ptr = text.into_glib_ptr();
608    *cursor_index_ptr = cursor_idx;
609    *attrs_ptr = attrs.into_glib_ptr();
610}
611
612unsafe extern "C" fn im_context_get_surrounding<T: IMContextImpl>(
613    ptr: *mut ffi::GtkIMContext,
614    text_ptr: *mut *mut libc::c_char,
615    cursor_index_ptr: *mut libc::c_int,
616) -> glib::ffi::gboolean {
617    let instance = &*(ptr as *mut T::Instance);
618    let imp = instance.imp();
619
620    if let Some((text, cursor_idx)) = imp.surrounding() {
621        *text_ptr = text.into_glib_ptr();
622        *cursor_index_ptr = cursor_idx;
623        true.into_glib()
624    } else {
625        *text_ptr = std::ptr::null_mut();
626        *cursor_index_ptr = 0;
627        false.into_glib()
628    }
629}
630
631unsafe extern "C" fn im_context_preedit_changed<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
632    let instance = &*(ptr as *mut T::Instance);
633    let imp = instance.imp();
634
635    imp.preedit_changed()
636}
637
638unsafe extern "C" fn im_context_preedit_end<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
639    let instance = &*(ptr as *mut T::Instance);
640    let imp = instance.imp();
641
642    imp.preedit_end()
643}
644
645unsafe extern "C" fn im_context_preedit_start<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
646    let instance = &*(ptr as *mut T::Instance);
647    let imp = instance.imp();
648
649    imp.preedit_start()
650}
651
652unsafe extern "C" fn im_context_reset<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
653    let instance = &*(ptr as *mut T::Instance);
654    let imp = instance.imp();
655
656    imp.reset()
657}
658
659unsafe extern "C" fn im_context_retrieve_surrounding<T: IMContextImpl>(
660    ptr: *mut ffi::GtkIMContext,
661) -> glib::ffi::gboolean {
662    let instance = &*(ptr as *mut T::Instance);
663    let imp = instance.imp();
664
665    imp.retrieve_surrounding().into_glib()
666}
667
668unsafe extern "C" fn im_context_set_client_widget<T: IMContextImpl>(
669    ptr: *mut ffi::GtkIMContext,
670    widgetptr: *mut ffi::GtkWidget,
671) {
672    let instance = &*(ptr as *mut T::Instance);
673    let imp = instance.imp();
674    let widget: Borrowed<Option<Widget>> = from_glib_borrow(widgetptr);
675
676    imp.set_client_widget(widget.as_ref().as_ref());
677}
678
679unsafe extern "C" fn im_context_set_cursor_location<T: IMContextImpl>(
680    ptr: *mut ffi::GtkIMContext,
681    areaptr: *mut gdk::ffi::GdkRectangle,
682) {
683    let instance = &*(ptr as *mut T::Instance);
684    let imp = instance.imp();
685    let area = from_glib_borrow(areaptr);
686
687    imp.set_cursor_location(&area);
688}
689
690unsafe extern "C" fn im_context_set_surrounding<T: IMContextImpl>(
691    ptr: *mut ffi::GtkIMContext,
692    textptr: *const libc::c_char,
693    length: i32,
694    cursor_index: i32,
695) {
696    let instance = &*(ptr as *mut T::Instance);
697    let imp = instance.imp();
698    let text: Borrowed<GString> = from_glib_borrow(textptr);
699
700    // length == -1 if text is null-terminated
701    let text = if length == -1 {
702        &text[..]
703    } else {
704        &text[0..(length as usize)]
705    };
706
707    imp.set_surrounding(text, cursor_index)
708}
709
710unsafe extern "C" fn im_context_set_use_preedit<T: IMContextImpl>(
711    ptr: *mut ffi::GtkIMContext,
712    use_preedit: glib::ffi::gboolean,
713) {
714    let instance = &*(ptr as *mut T::Instance);
715    let imp = instance.imp();
716
717    imp.set_use_preedit(from_glib(use_preedit))
718}
719
720#[cfg(feature = "v4_10")]
721unsafe extern "C" fn im_context_activate_osk<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
722    let instance = &*(ptr as *mut T::Instance);
723    let imp = instance.imp();
724
725    imp.activate_osk()
726}
727
728#[cfg(feature = "v4_14")]
729unsafe extern "C" fn im_context_activate_osk_with_event<T: IMContextImpl>(
730    ptr: *mut ffi::GtkIMContext,
731    eventptr: *mut gdk::ffi::GdkEvent,
732) -> glib::ffi::gboolean {
733    let instance = &*(ptr as *mut T::Instance);
734    let imp = instance.imp();
735
736    let event: Borrowed<Option<gdk::Event>> = from_glib_borrow(eventptr);
737
738    imp.activate_osk_with_event(event.as_ref().as_ref())
739        .into_glib()
740}
741
742#[cfg(feature = "v4_22")]
743unsafe extern "C" fn im_context_invalid_composition<T: IMContextImpl>(
744    ptr: *mut ffi::GtkIMContext,
745    stringptr: *const libc::c_char,
746) -> glib::ffi::gboolean {
747    let instance = &*(ptr as *mut T::Instance);
748    let imp = instance.imp();
749    let text: Borrowed<GString> = from_glib_borrow(stringptr);
750
751    imp.invalid_composition(&text).into_glib()
752}