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