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`](crate::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: IMContextImplExt + ObjectImpl {
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}
227
228mod sealed {
229    pub trait Sealed {}
230    impl<T: super::IMContextImplExt> Sealed for T {}
231}
232
233#[allow(clippy::upper_case_acronyms)]
234pub trait IMContextImplExt: sealed::Sealed + ObjectSubclass {
235    fn parent_commit(&self, string: &str) {
236        unsafe {
237            let data = Self::type_data();
238            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
239            if let Some(f) = (*parent_class).commit {
240                f(
241                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
242                    string.to_glib_none().0,
243                );
244            }
245        }
246    }
247
248    // Returns true if the signal was handled
249    fn parent_delete_surrounding(&self, offset: i32, n_chars: i32) -> bool {
250        unsafe {
251            let data = Self::type_data();
252            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
253            if let Some(f) = (*parent_class).delete_surrounding {
254                from_glib(f(
255                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
256                    offset,
257                    n_chars,
258                ))
259            } else {
260                false
261            }
262        }
263    }
264
265    // Returns true if the event was consumed
266    fn parent_filter_keypress(&self, event: &gdk::Event) -> bool {
267        unsafe {
268            let data = Self::type_data();
269            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
270            if let Some(f) = (*parent_class).filter_keypress {
271                from_glib(f(
272                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
273                    event.to_glib_none().0,
274                ))
275            } else {
276                false
277            }
278        }
279    }
280
281    fn parent_focus_in(&self) {
282        unsafe {
283            let data = Self::type_data();
284            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
285            if let Some(f) = (*parent_class).focus_in {
286                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
287            }
288        }
289    }
290
291    fn parent_focus_out(&self) {
292        unsafe {
293            let data = Self::type_data();
294            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
295            if let Some(f) = (*parent_class).focus_out {
296                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
297            }
298        }
299    }
300
301    fn parent_surrounding(&self) -> Option<(GString, i32)> {
302        unsafe {
303            let data = Self::type_data();
304            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
305            if let Some(f) = (*parent_class).get_surrounding {
306                let mut text = std::ptr::null_mut();
307                let mut cursor_index = std::mem::MaybeUninit::uninit();
308                let ret = from_glib(f(
309                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
310                    &mut text,
311                    cursor_index.as_mut_ptr(),
312                ));
313                if ret {
314                    return Some((from_glib_full(text), cursor_index.assume_init()));
315                }
316            }
317            None
318        }
319    }
320
321    fn parent_preedit_string(&self) -> (GString, AttrList, i32) {
322        unsafe {
323            let data = Self::type_data();
324            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
325            let f = (*parent_class)
326                .get_preedit_string
327                .expect("No parent class impl for \"get_preedit_string\"");
328            let mut string = std::ptr::null_mut();
329            let mut attrs = std::ptr::null_mut();
330            let mut cursor_pos = std::mem::MaybeUninit::uninit();
331            f(
332                self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
333                &mut string,
334                &mut attrs,
335                cursor_pos.as_mut_ptr(),
336            );
337            (
338                from_glib_full(string),
339                from_glib_full(attrs),
340                cursor_pos.assume_init(),
341            )
342        }
343    }
344
345    fn parent_preedit_changed(&self) {
346        unsafe {
347            let data = Self::type_data();
348            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
349            if let Some(f) = (*parent_class).preedit_changed {
350                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
351            }
352        }
353    }
354
355    fn parent_preedit_end(&self) {
356        unsafe {
357            let data = Self::type_data();
358            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
359            if let Some(f) = (*parent_class).preedit_end {
360                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
361            }
362        }
363    }
364
365    fn parent_preedit_start(&self) {
366        unsafe {
367            let data = Self::type_data();
368            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
369            if let Some(f) = (*parent_class).preedit_start {
370                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
371            }
372        }
373    }
374
375    fn parent_reset(&self) {
376        unsafe {
377            let data = Self::type_data();
378            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
379            if let Some(f) = (*parent_class).reset {
380                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
381            }
382        }
383    }
384
385    // Returns true if the signal was handled
386    fn parent_retrieve_surrounding(&self) -> bool {
387        unsafe {
388            let data = Self::type_data();
389            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
390            if let Some(f) = (*parent_class).retrieve_surrounding {
391                from_glib(f(self
392                    .obj()
393                    .unsafe_cast_ref::<IMContext>()
394                    .to_glib_none()
395                    .0))
396            } else {
397                false
398            }
399        }
400    }
401
402    fn parent_set_client_widget<P: IsA<Widget>>(&self, widget: Option<&P>) {
403        unsafe {
404            let data = Self::type_data();
405            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
406            if let Some(f) = (*parent_class).set_client_widget {
407                f(
408                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
409                    widget.map(|p| p.as_ref()).to_glib_none().0,
410                )
411            }
412        }
413    }
414
415    fn parent_set_cursor_location(&self, area: &gdk::Rectangle) {
416        unsafe {
417            let data = Self::type_data();
418            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
419            if let Some(f) = (*parent_class).set_cursor_location {
420                f(
421                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
422                    area.to_glib_none().0 as *mut _,
423                );
424            }
425        }
426    }
427
428    #[cfg_attr(feature = "v4_2", deprecated = "Since 4.2")]
429    #[allow(deprecated)]
430    fn parent_set_surrounding(&self, text: &str, cursor_index: i32) {
431        unsafe {
432            let data = Self::type_data();
433            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
434            if let Some(f) = (*parent_class).set_surrounding {
435                f(
436                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
437                    text.to_glib_none().0,
438                    text.len() as i32,
439                    cursor_index,
440                )
441            }
442        }
443    }
444
445    fn parent_set_use_preedit(&self, use_preedit: 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).set_use_preedit {
450                f(
451                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
452                    use_preedit.into_glib(),
453                )
454            }
455        }
456    }
457
458    #[cfg(feature = "v4_10")]
459    #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
460    fn parent_activate_osk(&self) {
461        unsafe {
462            let data = Self::type_data();
463            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
464            if let Some(f) = (*parent_class).activate_osk {
465                f(self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0)
466            }
467        }
468    }
469
470    #[cfg(feature = "v4_14")]
471    #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
472    fn parent_activate_osk_with_event(&self, event: Option<&gdk::Event>) -> bool {
473        unsafe {
474            let data = Self::type_data();
475            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkIMContextClass;
476            if let Some(f) = (*parent_class).activate_osk_with_event {
477                from_glib(f(
478                    self.obj().unsafe_cast_ref::<IMContext>().to_glib_none().0,
479                    event.to_glib_none().0,
480                ))
481            } else {
482                false
483            }
484        }
485    }
486}
487
488impl<T: IMContextImpl> IMContextImplExt for T {}
489
490unsafe impl<T: IMContextImpl> IsSubclassable<T> for IMContext {
491    fn class_init(class: &mut glib::Class<Self>) {
492        Self::parent_class_init::<T>(class);
493
494        assert_initialized_main_thread!();
495
496        let klass = class.as_mut();
497        klass.commit = Some(im_context_commit::<T>);
498        klass.delete_surrounding = Some(im_context_delete_surrounding::<T>);
499        klass.filter_keypress = Some(im_context_filter_keypress::<T>);
500        klass.focus_in = Some(im_context_focus_in::<T>);
501        klass.focus_out = Some(im_context_focus_out::<T>);
502        klass.get_preedit_string = Some(im_context_get_preedit_string::<T>);
503        klass.get_surrounding = Some(im_context_get_surrounding::<T>);
504        klass.preedit_changed = Some(im_context_preedit_changed::<T>);
505        klass.preedit_end = Some(im_context_preedit_end::<T>);
506        klass.preedit_start = Some(im_context_preedit_start::<T>);
507        klass.reset = Some(im_context_reset::<T>);
508        klass.retrieve_surrounding = Some(im_context_retrieve_surrounding::<T>);
509        klass.set_client_widget = Some(im_context_set_client_widget::<T>);
510        klass.set_cursor_location = Some(im_context_set_cursor_location::<T>);
511        klass.set_surrounding = Some(im_context_set_surrounding::<T>);
512        klass.set_use_preedit = Some(im_context_set_use_preedit::<T>);
513        #[cfg(feature = "v4_10")]
514        #[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
515        {
516            klass.activate_osk = Some(im_context_activate_osk::<T>);
517        };
518        #[cfg(feature = "v4_14")]
519        #[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
520        {
521            klass.activate_osk_with_event = Some(im_context_activate_osk_with_event::<T>);
522        };
523    }
524}
525
526unsafe extern "C" fn im_context_commit<T: IMContextImpl>(
527    ptr: *mut ffi::GtkIMContext,
528    stringptr: *const libc::c_char,
529) {
530    let instance = &*(ptr as *mut T::Instance);
531    let imp = instance.imp();
532    let string: Borrowed<GString> = from_glib_borrow(stringptr);
533
534    imp.commit(string.as_str())
535}
536
537unsafe extern "C" fn im_context_delete_surrounding<T: IMContextImpl>(
538    ptr: *mut ffi::GtkIMContext,
539    offset: i32,
540    n_chars: i32,
541) -> glib::ffi::gboolean {
542    let instance = &*(ptr as *mut T::Instance);
543    let imp = instance.imp();
544
545    imp.delete_surrounding(offset, n_chars).into_glib()
546}
547
548unsafe extern "C" fn im_context_filter_keypress<T: IMContextImpl>(
549    ptr: *mut ffi::GtkIMContext,
550    eventptr: *mut gdk::ffi::GdkEvent,
551) -> glib::ffi::gboolean {
552    let instance = &*(ptr as *mut T::Instance);
553    let imp = instance.imp();
554    let event: Borrowed<gdk::Event> = from_glib_borrow(eventptr);
555    imp.filter_keypress(&event).into_glib()
556}
557
558unsafe extern "C" fn im_context_focus_in<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
559    let instance = &*(ptr as *mut T::Instance);
560    let imp = instance.imp();
561
562    imp.focus_in()
563}
564
565unsafe extern "C" fn im_context_focus_out<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
566    let instance = &*(ptr as *mut T::Instance);
567    let imp = instance.imp();
568
569    imp.focus_out()
570}
571
572unsafe extern "C" fn im_context_get_preedit_string<T: IMContextImpl>(
573    ptr: *mut ffi::GtkIMContext,
574    text_ptr: *mut *mut libc::c_char,
575    attrs_ptr: *mut *mut pango::ffi::PangoAttrList,
576    cursor_index_ptr: *mut libc::c_int,
577) {
578    let instance = &*(ptr as *mut T::Instance);
579    let imp = instance.imp();
580
581    let (text, attrs, cursor_idx) = imp.preedit_string();
582
583    *text_ptr = text.into_glib_ptr();
584    *cursor_index_ptr = cursor_idx;
585    *attrs_ptr = attrs.into_glib_ptr();
586}
587
588unsafe extern "C" fn im_context_get_surrounding<T: IMContextImpl>(
589    ptr: *mut ffi::GtkIMContext,
590    text_ptr: *mut *mut libc::c_char,
591    cursor_index_ptr: *mut libc::c_int,
592) -> glib::ffi::gboolean {
593    let instance = &*(ptr as *mut T::Instance);
594    let imp = instance.imp();
595
596    if let Some((text, cursor_idx)) = imp.surrounding() {
597        *text_ptr = text.into_glib_ptr();
598        *cursor_index_ptr = cursor_idx;
599        true.into_glib()
600    } else {
601        *text_ptr = std::ptr::null_mut();
602        *cursor_index_ptr = 0;
603        false.into_glib()
604    }
605}
606
607unsafe extern "C" fn im_context_preedit_changed<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
608    let instance = &*(ptr as *mut T::Instance);
609    let imp = instance.imp();
610
611    imp.preedit_changed()
612}
613
614unsafe extern "C" fn im_context_preedit_end<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
615    let instance = &*(ptr as *mut T::Instance);
616    let imp = instance.imp();
617
618    imp.preedit_end()
619}
620
621unsafe extern "C" fn im_context_preedit_start<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
622    let instance = &*(ptr as *mut T::Instance);
623    let imp = instance.imp();
624
625    imp.preedit_start()
626}
627
628unsafe extern "C" fn im_context_reset<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
629    let instance = &*(ptr as *mut T::Instance);
630    let imp = instance.imp();
631
632    imp.reset()
633}
634
635unsafe extern "C" fn im_context_retrieve_surrounding<T: IMContextImpl>(
636    ptr: *mut ffi::GtkIMContext,
637) -> glib::ffi::gboolean {
638    let instance = &*(ptr as *mut T::Instance);
639    let imp = instance.imp();
640
641    imp.retrieve_surrounding().into_glib()
642}
643
644unsafe extern "C" fn im_context_set_client_widget<T: IMContextImpl>(
645    ptr: *mut ffi::GtkIMContext,
646    widgetptr: *mut ffi::GtkWidget,
647) {
648    let instance = &*(ptr as *mut T::Instance);
649    let imp = instance.imp();
650    let widget: Borrowed<Option<Widget>> = from_glib_borrow(widgetptr);
651
652    imp.set_client_widget(widget.as_ref().as_ref());
653}
654
655unsafe extern "C" fn im_context_set_cursor_location<T: IMContextImpl>(
656    ptr: *mut ffi::GtkIMContext,
657    areaptr: *mut gdk::ffi::GdkRectangle,
658) {
659    let instance = &*(ptr as *mut T::Instance);
660    let imp = instance.imp();
661    let area = from_glib_borrow(areaptr);
662
663    imp.set_cursor_location(&area);
664}
665
666unsafe extern "C" fn im_context_set_surrounding<T: IMContextImpl>(
667    ptr: *mut ffi::GtkIMContext,
668    textptr: *const libc::c_char,
669    length: i32,
670    cursor_index: i32,
671) {
672    let instance = &*(ptr as *mut T::Instance);
673    let imp = instance.imp();
674    let text: Borrowed<GString> = from_glib_borrow(textptr);
675
676    // length == -1 if text is null-terminated
677    let text = if length == -1 {
678        &text[..]
679    } else {
680        &text[0..(length as usize)]
681    };
682
683    imp.set_surrounding(text, cursor_index)
684}
685
686unsafe extern "C" fn im_context_set_use_preedit<T: IMContextImpl>(
687    ptr: *mut ffi::GtkIMContext,
688    use_preedit: glib::ffi::gboolean,
689) {
690    let instance = &*(ptr as *mut T::Instance);
691    let imp = instance.imp();
692
693    imp.set_use_preedit(from_glib(use_preedit))
694}
695
696#[cfg(feature = "v4_10")]
697#[cfg_attr(docsrs, doc(cfg(feature = "v4_10")))]
698unsafe extern "C" fn im_context_activate_osk<T: IMContextImpl>(ptr: *mut ffi::GtkIMContext) {
699    let instance = &*(ptr as *mut T::Instance);
700    let imp = instance.imp();
701
702    imp.activate_osk()
703}
704
705#[cfg(feature = "v4_14")]
706#[cfg_attr(docsrs, doc(cfg(feature = "v4_14")))]
707unsafe extern "C" fn im_context_activate_osk_with_event<T: IMContextImpl>(
708    ptr: *mut ffi::GtkIMContext,
709    eventptr: *mut gdk::ffi::GdkEvent,
710) -> glib::ffi::gboolean {
711    let instance = &*(ptr as *mut T::Instance);
712    let imp = instance.imp();
713
714    let event: Borrowed<Option<gdk::Event>> = from_glib_borrow(eventptr);
715
716    imp.activate_osk_with_event(event.as_ref().as_ref())
717        .into_glib()
718}