Skip to main content

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::{GString, translate::*};
7use pango::AttrList;
8
9use crate::{IMContext, Widget, ffi, prelude::*, subclass::prelude::*};
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 surrounding context around the insertion point and preedit
206    /// string. This function is expected to be called in response to the
207    /// [`retrieve_surrounding`][struct@crate::IMContext#retrieve_surrounding] signal, and will likely
208    /// have no effect if called at other times.
209    /// ## `text`
210    /// text surrounding the insertion point, as UTF-8.
211    ///   the preedit string should not be included within @text
212    /// ## `len`
213    /// the length of @text, or -1 if @text is nul-terminated
214    /// ## `cursor_index`
215    /// the byte index of the insertion cursor within @text
216    /// ## `anchor_index`
217    /// the byte index of the selection bound within @text
218    #[cfg(feature = "v4_2")]
219    #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
220    fn set_surrounding_with_selection(&self, text: &str, cursor_index: i32, anchor_index: i32) {
221        self.parent_set_surrounding_with_selection(text, cursor_index, anchor_index)
222    }
223    /// Retrieves context around the insertion point.
224    ///
225    /// Input methods typically want context in order to constrain input
226    /// text based on existing text; this is important for languages such
227    /// as Thai where only some sequences of characters are allowed.
228    ///
229    /// This function is implemented by emitting the
230    /// [`retrieve-surrounding`][struct@crate::IMContext#retrieve-surrounding] signal on the input method;
231    /// in response to this signal, a widget should provide as much context as
232    /// is available, up to an entire paragraph, by calling
233    /// [`IMContextExt::set_surrounding_with_selection()`][crate::prelude::IMContextExt::set_surrounding_with_selection()].
234    ///
235    /// Note that there is no obligation for a widget to respond to the
236    /// `::retrieve-surrounding` signal, so input methods must be prepared to
237    /// function without context.
238    ///
239    /// # Returns
240    ///
241    /// `TRUE` if surrounding text was provided; in this case
242    ///   you must free the result stored in `text`.
243    ///
244    /// ## `text`
245    /// location to store a UTF-8 encoded
246    ///   string of text holding context around the insertion point.
247    ///   If the function returns [`true`], then you must free the result
248    ///   stored in this location with g_free().
249    ///
250    /// ## `cursor_index`
251    /// location to store byte index of the insertion
252    ///   cursor within @text.
253    ///
254    /// ## `anchor_index`
255    /// location to store byte index of the selection
256    ///   bound within @text
257    #[cfg(feature = "v4_2")]
258    #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
259    fn surrounding_with_selection(&self) -> Option<(glib::GString, i32, i32)> {
260        self.parent_surrounding_with_selection()
261    }
262    /// Sets whether the IM context should use the preedit string
263    /// to display feedback.
264    ///
265    /// If @use_preedit is [`false`] (default is [`true`]), then the IM context
266    /// may use some other method to display feedback, such as displaying
267    /// it in a child of the root window.
268    /// ## `use_preedit`
269    /// whether the IM context should use the preedit string.
270    fn set_use_preedit(&self, use_preedit: bool) {
271        self.parent_set_use_preedit(use_preedit)
272    }
273    #[cfg(feature = "v4_10")]
274    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
275    fn activate_osk(&self) {
276        self.parent_activate_osk()
277    }
278    #[cfg(feature = "v4_14")]
279    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
280    fn activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
281        self.parent_activate_osk_with_event(event)
282    }
283    /// Default handler of the
284    ///   [`invalid-composition`][struct@crate::IMContext#invalid-composition] signal. Since: 4.22
285    #[cfg(feature = "v4_22")]
286    #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
287    fn invalid_composition(&self, string: &str) -> bool {
288        self.parent_invalid_composition(string)
289    }
290}
291
292#[allow(clippy::upper_case_acronyms)]
293pub trait IMContextImplExt: IMContextImpl {
294    fn parent_commit(&self, string: &str) {
295        unsafe {
296            let data = Self::type_data();
297            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
298            if let Some(f) = (*parent_class).commit {
299                f(
300                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
301                    string.to_glib_none().0,
302                );
303            }
304        }
305    }
306
307    // Returns true if the signal was handled
308    fn parent_delete_surrounding(&self, offset: i32, n_chars: i32) -> bool {
309        unsafe {
310            let data = Self::type_data();
311            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
312            if let Some(f) = (*parent_class).delete_surrounding {
313                from_glib(f(
314                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
315                    offset,
316                    n_chars,
317                ))
318            } else {
319                false
320            }
321        }
322    }
323
324    // Returns true if the event was consumed
325    fn parent_filter_keypress(&self, event: &gdk::Event) -> bool {
326        unsafe {
327            let data = Self::type_data();
328            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
329            if let Some(f) = (*parent_class).filter_keypress {
330                from_glib(f(
331                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
332                    event.to_glib_none().0,
333                ))
334            } else {
335                false
336            }
337        }
338    }
339
340    fn parent_focus_in(&self) {
341        unsafe {
342            let data = Self::type_data();
343            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
344            if let Some(f) = (*parent_class).focus_in {
345                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
346            }
347        }
348    }
349
350    fn parent_focus_out(&self) {
351        unsafe {
352            let data = Self::type_data();
353            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
354            if let Some(f) = (*parent_class).focus_out {
355                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
356            }
357        }
358    }
359
360    fn parent_surrounding(&self) -> Option<(GString, i32)> {
361        unsafe {
362            let data = Self::type_data();
363            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
364            if let Some(f) = (*parent_class).get_surrounding {
365                let mut text = std::ptr::null_mut();
366                let mut cursor_index = std::mem::MaybeUninit::uninit();
367                let ret = from_glib(f(
368                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
369                    &mut text,
370                    cursor_index.as_mut_ptr(),
371                ));
372                if ret {
373                    return Some((from_glib_full(text), cursor_index.assume_init()));
374                }
375            }
376            None
377        }
378    }
379
380    fn parent_preedit_string(&self) -> (GString, AttrList, i32) {
381        unsafe {
382            let data = Self::type_data();
383            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
384            let f = (*parent_class)
385                .get_preedit_string
386                .expect("No parent class impl for \"get_preedit_string\"");
387            let mut string = std::ptr::null_mut();
388            let mut attrs = std::ptr::null_mut();
389            let mut cursor_pos = std::mem::MaybeUninit::uninit();
390            f(
391                self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
392                &mut string,
393                &mut attrs,
394                cursor_pos.as_mut_ptr(),
395            );
396            (
397                from_glib_full(string),
398                from_glib_full(attrs),
399                cursor_pos.assume_init(),
400            )
401        }
402    }
403
404    fn parent_preedit_changed(&self) {
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).preedit_changed {
409                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
410            }
411        }
412    }
413
414    fn parent_preedit_end(&self) {
415        unsafe {
416            let data = Self::type_data();
417            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
418            if let Some(f) = (*parent_class).preedit_end {
419                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
420            }
421        }
422    }
423
424    fn parent_preedit_start(&self) {
425        unsafe {
426            let data = Self::type_data();
427            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
428            if let Some(f) = (*parent_class).preedit_start {
429                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
430            }
431        }
432    }
433
434    fn parent_reset(&self) {
435        unsafe {
436            let data = Self::type_data();
437            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
438            if let Some(f) = (*parent_class).reset {
439                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
440            }
441        }
442    }
443
444    // Returns true if the signal was handled
445    fn parent_retrieve_surrounding(&self) -> bool {
446        unsafe {
447            let data = Self::type_data();
448            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
449            if let Some(f) = (*parent_class).retrieve_surrounding {
450                from_glib(f(self
451                    .obj()
452                    .unsafe_cast_ref::<IMContext>()
453                    .to_glib_none()
454                    .0))
455            } else {
456                false
457            }
458        }
459    }
460
461    fn parent_set_client_widget<P: IsA<Widget>>(&self, widget: Option<&P>) {
462        unsafe {
463            let data = Self::type_data();
464            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
465            if let Some(f) = (*parent_class).set_client_widget {
466                f(
467                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
468                    widget.map(|p| p.as_ref()).to_glib_none().0,
469                )
470            }
471        }
472    }
473
474    fn parent_set_cursor_location(&self, area: &gdk::Rectangle) {
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).set_cursor_location {
479                f(
480                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
481                    area.to_glib_none().0 as *mut _,
482                );
483            }
484        }
485    }
486
487    #[cfg_attr(feature = "v4_2", deprecated = "Since 4.2")]
488    #[allow(deprecated)]
489    fn parent_set_surrounding(&self, text: &str, cursor_index: i32) {
490        unsafe {
491            let data = Self::type_data();
492            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
493            if let Some(f) = (*parent_class).set_surrounding {
494                f(
495                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
496                    text.to_glib_none().0,
497                    text.len() as i32,
498                    cursor_index,
499                )
500            }
501        }
502    }
503
504    #[cfg(feature = "v4_2")]
505    #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
506    fn parent_set_surrounding_with_selection(
507        &self,
508        text: &str,
509        cursor_index: i32,
510        anchor_index: i32,
511    ) {
512        unsafe {
513            let data = Self::type_data();
514            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
515            if let Some(f) = (*parent_class).set_surrounding_with_selection {
516                f(
517                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
518                    text.to_glib_none().0,
519                    text.len() as i32,
520                    cursor_index,
521                    anchor_index,
522                )
523            }
524        }
525    }
526    #[cfg(feature = "v4_2")]
527    #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
528    fn parent_surrounding_with_selection(&self) -> Option<(glib::GString, i32, i32)> {
529        unsafe {
530            let data = Self::type_data();
531            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
532            if let Some(f) = (*parent_class).get_surrounding_with_selection {
533                let mut cursor_index = std::mem::MaybeUninit::uninit();
534                let mut anchor_index = std::mem::MaybeUninit::uninit();
535                let mut text = std::ptr::null_mut();
536                let res = f(
537                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
538                    &mut text,
539                    cursor_index.as_mut_ptr(),
540                    anchor_index.as_mut_ptr(),
541                );
542                if from_glib(res) {
543                    Some((
544                        glib::GString::from_glib_none(text),
545                        cursor_index.assume_init(),
546                        anchor_index.assume_init(),
547                    ))
548                } else {
549                    None
550                }
551            } else {
552                None
553            }
554        }
555    }
556
557    fn parent_set_use_preedit(&self, use_preedit: bool) {
558        unsafe {
559            let data = Self::type_data();
560            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
561            if let Some(f) = (*parent_class).set_use_preedit {
562                f(
563                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
564                    use_preedit.into_glib(),
565                )
566            }
567        }
568    }
569
570    #[cfg(feature = "v4_10")]
571    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
572    fn parent_activate_osk(&self) {
573        unsafe {
574            let data = Self::type_data();
575            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
576            if let Some(f) = (*parent_class).activate_osk {
577                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
578            }
579        }
580    }
581
582    #[cfg(feature = "v4_14")]
583    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
584    fn parent_activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
585        unsafe {
586            let data = Self::type_data();
587            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
588            if let Some(f) = (*parent_class).activate_osk_with_event {
589                from_glib(f(
590                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
591                    event.to_glib_none().0,
592                ))
593            } else {
594                false
595            }
596        }
597    }
598
599    #[cfg(feature = "v4_22")]
600    #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
601    fn parent_invalid_composition(&self, string: &str) -> bool {
602        unsafe {
603            let data = Self::type_data();
604            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
605            if let Some(f) = (*parent_class).invalid_composition {
606                from_glib(f(
607                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
608                    string.to_glib_none().0,
609                ))
610            } else {
611                false
612            }
613        }
614    }
615}
616
617impl<T: IMContextImpl> IMContextImplExt for T {}
618
619unsafe impl<T: IMContextImpl> IsSubclassable<T> for IMContext {
620    fn class_init(class: &mut glib::Class<Self>) {
621        Self::parent_class_init::<T>(class);
622
623        assert_initialized_main_thread!();
624
625        let klass = class.as_mut();
626        klass.commit = Some(im_context_commit::<T>);
627        klass.delete_surrounding = Some(im_context_delete_surrounding::<T>);
628        klass.filter_keypress = Some(im_context_filter_keypress::<T>);
629        klass.focus_in = Some(im_context_focus_in::<T>);
630        klass.focus_out = Some(im_context_focus_out::<T>);
631        klass.get_preedit_string = Some(im_context_get_preedit_string::<T>);
632        klass.get_surrounding = Some(im_context_get_surrounding::<T>);
633        klass.preedit_changed = Some(im_context_preedit_changed::<T>);
634        klass.preedit_end = Some(im_context_preedit_end::<T>);
635        klass.preedit_start = Some(im_context_preedit_start::<T>);
636        klass.reset = Some(im_context_reset::<T>);
637        klass.retrieve_surrounding = Some(im_context_retrieve_surrounding::<T>);
638        klass.set_client_widget = Some(im_context_set_client_widget::<T>);
639        klass.set_cursor_location = Some(im_context_set_cursor_location::<T>);
640        klass.set_surrounding = Some(im_context_set_surrounding::<T>);
641        klass.set_use_preedit = Some(im_context_set_use_preedit::<T>);
642        #[cfg(feature = "v4_2")]
643        #[cfg_attr(docsrs, doc(cfg(feature = "v4_2")))]
644        {
645            klass.set_surrounding_with_selection =
646                Some(im_context_set_surrounding_with_selection::<T>);
647            klass.get_surrounding_with_selection =
648                Some(im_context_get_surrounding_with_selection::<T>);
649        };
650        #[cfg(feature = "v4_10")]
651        #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
652        {
653            klass.activate_osk = Some(im_context_activate_osk::<T>);
654        };
655        #[cfg(feature = "v4_14")]
656        #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
657        {
658            klass.activate_osk_with_event = Some(im_context_activate_osk_with_event::<T>);
659        };
660        #[cfg(feature = "v4_22")]
661        #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
662        {
663            klass.invalid_composition = Some(im_context_invalid_composition::<T>);
664        };
665    }
666}
667
668unsafe extern "C" fn im_context_commit<T: IMContextImpl>(
669    ptr: *mut ffi::GtkIMContext,
670    stringptr: *const libc::c_char,
671) {
672    unsafe {
673        let instance = &*(ptr as *mut T::Instance);
674        let imp = instance.imp();
675        let string: Borrowed<GString> = from_glib_borrow(stringptr);
676
677        imp.commit(string.as_str())
678    }
679}
680
681unsafe extern "C" fn im_context_delete_surrounding<T: IMContextImpl>(
682    ptr: *mut ffi::GtkIMContext,
683    offset: i32,
684    n_chars: i32,
685) -> glib::ffi::gboolean {
686    unsafe {
687        let instance = &*(ptr as *mut T::Instance);
688        let imp = instance.imp();
689
690        imp.delete_surrounding(offset, n_chars).into_glib()
691    }
692}
693
694unsafe extern "C" fn im_context_filter_keypress<T: IMContextImpl>(
695    ptr: *mut ffi::GtkIMContext,
696    eventptr: *mut gdk::ffi::GdkEvent,
697) -> glib::ffi::gboolean {
698    unsafe {
699        let instance = &*(ptr as *mut T::Instance);
700        let imp = instance.imp();
701        let event: Borrowed<gdk::Event> = from_glib_borrow(eventptr);
702        imp.filter_keypress(&event).into_glib()
703    }
704}
705
706unsafe extern "C" fn im_context_focus_in<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
707    unsafe {
708        let instance = &*(ptr as *mut T::Instance);
709        let imp = instance.imp();
710
711        imp.focus_in()
712    }
713}
714
715unsafe extern "C" fn im_context_focus_out<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
716    unsafe {
717        let instance = &*(ptr as *mut T::Instance);
718        let imp = instance.imp();
719
720        imp.focus_out()
721    }
722}
723
724unsafe extern "C" fn im_context_get_preedit_string<T: IMContextImpl>(
725    ptr: *mut ffi::GtkIMContext,
726    text_ptr: *mut *mut libc::c_char,
727    attrs_ptr: *mut *mut pango::ffi::PangoAttrList,
728    cursor_index_ptr: *mut libc::c_int,
729) {
730    unsafe {
731        let instance = &*(ptr as *mut T::Instance);
732        let imp = instance.imp();
733
734        let (text, attrs, cursor_idx) = imp.preedit_string();
735
736        *text_ptr = text.into_glib_ptr();
737        *cursor_index_ptr = cursor_idx;
738        *attrs_ptr = attrs.into_glib_ptr();
739    }
740}
741
742unsafe extern "C" fn im_context_get_surrounding<T: IMContextImpl>(
743    ptr: *mut ffi::GtkIMContext,
744    text_ptr: *mut *mut libc::c_char,
745    cursor_index_ptr: *mut libc::c_int,
746) -> glib::ffi::gboolean {
747    unsafe {
748        let instance = &*(ptr as *mut T::Instance);
749        let imp = instance.imp();
750
751        match imp.surrounding() {
752            Some((text, cursor_idx)) => {
753                *text_ptr = text.into_glib_ptr();
754                *cursor_index_ptr = cursor_idx;
755                true.into_glib()
756            }
757            _ => {
758                *text_ptr = std::ptr::null_mut();
759                *cursor_index_ptr = 0;
760                false.into_glib()
761            }
762        }
763    }
764}
765
766unsafe extern "C" fn im_context_preedit_changed<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
767    unsafe {
768        let instance = &*(ptr as *mut T::Instance);
769        let imp = instance.imp();
770
771        imp.preedit_changed()
772    }
773}
774
775unsafe extern "C" fn im_context_preedit_end<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
776    unsafe {
777        let instance = &*(ptr as *mut T::Instance);
778        let imp = instance.imp();
779
780        imp.preedit_end()
781    }
782}
783
784unsafe extern "C" fn im_context_preedit_start<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
785    unsafe {
786        let instance = &*(ptr as *mut T::Instance);
787        let imp = instance.imp();
788
789        imp.preedit_start()
790    }
791}
792
793unsafe extern "C" fn im_context_reset<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
794    unsafe {
795        let instance = &*(ptr as *mut T::Instance);
796        let imp = instance.imp();
797
798        imp.reset()
799    }
800}
801
802unsafe extern "C" fn im_context_retrieve_surrounding<T: IMContextImpl>(
803    ptr: *mut ffi::GtkIMContext,
804) -> glib::ffi::gboolean {
805    unsafe {
806        let instance = &*(ptr as *mut T::Instance);
807        let imp = instance.imp();
808
809        imp.retrieve_surrounding().into_glib()
810    }
811}
812
813unsafe extern "C" fn im_context_set_client_widget<T: IMContextImpl>(
814    ptr: *mut ffi::GtkIMContext,
815    widgetptr: *mut ffi::GtkWidget,
816) {
817    unsafe {
818        let instance = &*(ptr as *mut T::Instance);
819        let imp = instance.imp();
820        let widget: Borrowed<Option<Widget>> = from_glib_borrow(widgetptr);
821
822        imp.set_client_widget(widget.as_ref().as_ref());
823    }
824}
825
826unsafe extern "C" fn im_context_set_cursor_location<T: IMContextImpl>(
827    ptr: *mut ffi::GtkIMContext,
828    areaptr: *mut gdk::ffi::GdkRectangle,
829) {
830    unsafe {
831        let instance = &*(ptr as *mut T::Instance);
832        let imp = instance.imp();
833        let area = from_glib_borrow(areaptr);
834
835        imp.set_cursor_location(&area);
836    }
837}
838
839unsafe extern "C" fn im_context_set_surrounding<T: IMContextImpl>(
840    ptr: *mut ffi::GtkIMContext,
841    textptr: *const libc::c_char,
842    length: i32,
843    cursor_index: i32,
844) {
845    unsafe {
846        let instance = &*(ptr as *mut T::Instance);
847        let imp = instance.imp();
848        let text: Borrowed<GString> = from_glib_borrow(textptr);
849
850        // length == -1 if text is null-terminated
851        let text = if length == -1 {
852            &text[..]
853        } else {
854            &text[0..(length as usize)]
855        };
856
857        imp.set_surrounding(text, cursor_index)
858    }
859}
860
861unsafe extern "C" fn im_context_set_use_preedit<T: IMContextImpl>(
862    ptr: *mut ffi::GtkIMContext,
863    use_preedit: glib::ffi::gboolean,
864) {
865    unsafe {
866        let instance = &*(ptr as *mut T::Instance);
867        let imp = instance.imp();
868
869        imp.set_use_preedit(from_glib(use_preedit))
870    }
871}
872
873#[cfg(feature = "v4_2")]
874unsafe extern "C" fn im_context_set_surrounding_with_selection<T: IMContextImpl>(
875    ptr: *mut ffi::GtkIMContext,
876    text: *const libc::c_char,
877    len: i32,
878    cursor_index: i32,
879    anchor_index: i32,
880) {
881    let instance = unsafe { &*(ptr as *mut T::Instance) };
882    let imp = instance.imp();
883    let text = unsafe { glib::GStr::from_ptr(text) };
884    let text = if len == -1 {
885        text.as_str()
886    } else {
887        &text[..len as usize]
888    };
889
890    imp.set_surrounding_with_selection(text, cursor_index, anchor_index)
891}
892
893#[cfg(feature = "v4_2")]
894unsafe extern "C" fn im_context_get_surrounding_with_selection<T: IMContextImpl>(
895    ptr: *mut ffi::GtkIMContext,
896    textptr: *mut *mut libc::c_char,
897    cursor_indexptr: *mut libc::c_int,
898    anchor_indexptr: *mut libc::c_int,
899) -> glib::ffi::gboolean {
900    let instance = unsafe { &*(ptr as *mut T::Instance) };
901    let imp = instance.imp();
902    match imp.surrounding_with_selection() {
903        Some((text, cursor_index, anchor_index)) => {
904            unsafe {
905                *cursor_indexptr = cursor_index;
906                *anchor_indexptr = anchor_index;
907                *textptr = text.into_glib_ptr();
908            }
909            true.into_glib()
910        }
911        None => false.into_glib(),
912    }
913}
914
915#[cfg(feature = "v4_10")]
916unsafe extern "C" fn im_context_activate_osk<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
917    unsafe {
918        let instance = &*(ptr as *mut T::Instance);
919        let imp = instance.imp();
920
921        imp.activate_osk()
922    }
923}
924
925#[cfg(feature = "v4_14")]
926unsafe extern "C" fn im_context_activate_osk_with_event<T: IMContextImpl>(
927    ptr: *mut ffi::GtkIMContext,
928    eventptr: *mut gdk::ffi::GdkEvent,
929) -> glib::ffi::gboolean {
930    unsafe {
931        let instance = &*(ptr as *mut T::Instance);
932        let imp = instance.imp();
933
934        let event: Borrowed<Option<gdk::Event>> = from_glib_borrow(eventptr);
935
936        imp.activate_osk_with_event(event.as_ref().as_ref())
937            .into_glib()
938    }
939}
940
941#[cfg(feature = "v4_22")]
942unsafe extern "C" fn im_context_invalid_composition<T: IMContextImpl>(
943    ptr: *mut ffi::GtkIMContext,
944    stringptr: *const libc::c_char,
945) -> glib::ffi::gboolean {
946    unsafe {
947        let instance = &*(ptr as *mut T::Instance);
948        let imp = instance.imp();
949        let text: Borrowed<GString> = from_glib_borrow(stringptr);
950
951        imp.invalid_composition(&text).into_glib()
952    }
953}